# PLUR Brand Guidelines

> **Source of truth:** [`tokens.json`](tokens.json). `tokens.css` and everything in
> `assets/` are generated by `build_assets.py` — edit the JSON, never the outputs.
>
> Designed 19-page version: [`brand-guide.html`](brand-guide.html) · [PDF](PLUR-Brand-Guide.pdf)

PLUR is the open standard for AI agent memory. This document defines the mark,
palette, typography, design language and application rules.

---

## 1. The idea

> **Voice note.** "Decay" is accurate as *mechanism* — engrams strengthen with use
> and decay when irrelevant — and it stays in §3 where the animation is specified.
> It does not belong in headlines or marketing copy, where it foregrounds the exact
> thing a buyer fears. The pillar is **provable forgetting**: the same mechanic
> framed as control rather than loss. The site promises "remember forever"; nothing
> outward-facing should contradict that.

The mark is not a logo that moves. It is a process that occasionally spells our name.

Nine dots rest on a 3×3 grid, pulsing faintly and independently. Four fire in
sequence — growing, taking colour, connecting — and letters resolve inside them.
The mark holds, then releases and the grid returns to rest. Then it fires somewhere else.

The cycle alternates between the **home path**, which spells P L U R, and a
**random four-node path**, which spells nothing. The network wanders, and
periodically remembers what it is called.

That behaviour is the brand argument. A memory is not a stored object; it is a
pattern that fires, holds, and can fire again. Competitors draw a
brain, a chip, or a chat bubble. We draw the mechanism.

**When a design decision is unclear, the test is whether it makes the firing more legible.**

---

## 1a. Naming

**The product is PLUR** — uppercase, in the mark, in running text, in code
(`plur`, `@plur-ai/*`, `~/.plur/`), and in speech. `plur.ai` is a **domain, not a
name**: it belongs in a call to action, a footer, or a business card, never in the
logo. A domain is an address and addresses change; `.ai` is Anguilla's ccTLD and
its pricing and policy sit outside our control.

## 1b. Charter — Peace, Love, Unity, Respect

**PLUR is our ethical charter**, claimed deliberately from rave culture. It is the
shortest accurate statement of how we think memory should work: **owned in peace,
shared in love, held in unity, deleted on respect.**

The mark has exactly four fired nodes and the charter has exactly four words, so each
node carries several readings at once without a single change to the geometry:

| Node | Letter | Charter | Product value |
|---|---|---|---|
| Cyan · 1 | P | Peace | Verifiable |
| Amber · 2 | L | Love | Portable |
| Violet · 3 | U | Unity | Future-proof |
| Emerald · 4 | R | Respect | Private |

This is already live on plur.ai — the values section is a two-by-two mini-mark whose
source carries the comment `Row 1: Peace — bar — Love` on those same four accents.

**Where applicable, not everywhere.** The charter belongs in community, culture and
origin contexts. Enterprise material leads with the product values on the same accents.
The mapping is a depth cue, never the headline.

## 2. The mark

### Construction

- **viewBox** 200 × 200
- **Grid** 3 × 3, centres at 40 / 100 / 160 on both axes
- **Node indices** 0–8, left-to-right, top-to-bottom
- **Home path** `[0, 4, 5, 8]` — a descending diagonal step, which reads as
  forward motion rather than a static square

| Property | Resting | Fired |
|---|---|---|
| Node radius | 7 | 21 |
| Node fill | `--dim` | accent |
| Node opacity | 0.7–0.04 (pulsing) | 0.88 |
| Bar stroke | — | 11, round cap |
| Bar opacity | 0 | 0.72 |
| Letter | hidden | Outfit 900, em 32, filled `--bg` |

The **five latent dots are part of the mark, not decoration.** They are what makes
the four fired nodes read as *selected*. Do not remove them except at the minimum
sizes noted below.

### Static vs animated

The animated form is primary. The static form is the **home frame** — the moment
the mark spells PLUR — and is what all fixed assets use.

| Asset | Use |
|---|---|
| `assets/mark.svg` | Full colour, dark grounds |
| `assets/mark-reversed.svg` | Full colour, light grounds (latent dots darken) |
| `assets/mark-mono-light.svg` | Single colour white — dark grounds, embroidery, etch |
| `assets/mark-mono-dark.svg` | Single colour near-black — light grounds, one-colour print |
| `assets/wordmark.svg` / `-light.svg` | Wordmark — **PLUR**, Outfit 200 |
| `assets/wordmark-url.svg` / `-url-light.svg` | Domain form — **plur.ai**, for end cards and footers |
| `assets/mark-reduced.svg` / `-light.svg` | **Dots only**, no letters — below the floor, and inside lockups |
| `assets/lockup-h.svg` / `-light.svg` | Horizontal lockup — reduced mark + PLUR, cap 55% of mark height |
| `assets/lockup-stacked.svg` / `-light.svg` | Stacked lockup |

All letters are **outlined paths, not `<text>`** — the assets render correctly on
machines without Outfit installed. Never re-cut them with live text.

### Lockups

**The lockup uses the reduced mark — dots only — with PLUR set beside it in Outfit 300.**

The full mark already spells PLUR, so pairing it with a wordmark says the name twice
and prints the answer next to the puzzle, contradicting the rule against back-to-back
resolution in §3. Stripping the letters makes the mark a pure symbol and lets the type
carry the name. Nothing is doubled, and it reuses the reduced form already required
below the 48 px floor rather than inventing a third asset.

- **Mark alone** (with letters) — anywhere it appears above 48 px on its own: avatars,
  favicons at size, stickers, video end cards.
- **Lockup** (dots + PLUR) — horizontal contexts, cold audiences, and anywhere the name
  must appear in searchable or readable type.
- **Never** the full lettered mark beside a wordmark.

The gap between mark and wordmark is one grid unit — the same measure as clear space.

Wordmark weight is 300 rather than the 200 a display role would suggest: a wordmark
must survive small reproduction, and the mark already supplies the visual weight.

### Clear space

**One grid unit (60 units at viewBox 200 — 30% of mark width) on every side**,
measured from the mark's bounding box, not the viewBox edge. Nothing enters it:
no type, no rules, no image edges, no other logos.

In lockups the gap between mark and wordmark is exactly one grid unit.

### Minimum size

| Context | Minimum | What fails below it |
|---|---|---|
| Digital | **48 px** | **The letters.** They blur to lozenges — the mark stops saying its name |
| Print | 10 mm | Knocked-out counters close on uncoated stock — needs a physical proof |
| Embroidery | 55 mm | Reversed counters fall under thread gauge |

**The failing element is the letters, not the latent dots.** The dots survive well
below 48 px; the letters do not. Verified by render at 28/32/36/40/44/48/56 px:
mush below 36, marginal at 40, clean at 48.

This floor was ~64 px before the 2026-08-18 letter correction (em 25 to 36,
weight 700 to 600). Two independent evaluators found the letters were 42% of disc
diameter against a 55–65% convention, and that weight 700 closed the R's counter
to 1.13× its own stem. Enlarging them roughly halved the minimum size.

Below the minimum, use a **reduced four-node form**. Do not simply scale the full
mark down.

**The reduced form drops the letters.** Below the floor the mark works by visual
recognition — grid, path shape, colour sequence — not by spelling. A favicon does
not need to be read, it needs to be recognised.

### Misuse

Do not:

- Recolour the accents, or reassign which node gets which colour
- Use the accents semantically (status, category, severity) — see §4
- Rotate, skew, stretch, or reflow the grid
- Add effects: glow, bevel, drop shadow, outline, gradient overlay
- Place the mark on a busy image without a solid or heavily darkened plate
- Re-typeset the letters in another face or weight
- Loop the home path back to back — the wander is what makes resolution mean something
- Use the mark as a bullet, spinner, or loading indicator

---

## 3. Motion

The mark has no correct static form in the abstract; a still is one frame of an
animation. Reproduce the timing exactly — it is as much the identity as the geometry.

| Phase | Duration | Easing | Behaviour |
|---|---|---|---|
| Rest | 2500–4000 ms | ease-in-out | Nine dots pulse; each gets a random 2–4 s period and 0–2.5 s delay so they never sync |
| Node step | 500 ms | `cubic-bezier(.4,0,.2,1)` | Interval between consecutive nodes firing |
| Letter reveal | +160 ms | ease-in-out | After its node fires — the node arrives, then it is named |
| Bar draw | +260 ms | ease-out | Via `stroke-dashoffset`, previous node toward new |
| Hold (home) | 6000 ms | — | Longer when it spells PLUR |
| Hold (wander) | 3500 ms | — | Shorter when it spells nothing |
| Dissolve | 900 ms | ease | Letters out, bars retract along their path, nodes shrink |

Two details are load-bearing and easy to lose in a rebuild:

1. **Desynchronised rest** keeps the grid alive rather than blinking as a block.
2. **Bars retract along their path** on dissolve rather than fading — the
   connection is withdrawn, not switched off.

### Afterimages

On dissolve each fired node leaves a **blurred trace of its own colour** that
expands slightly and decays — spawned in the order the nodes fired, so the trace
decays the way it formed.

| Parameter | Value |
|---|---|
| Duration | 620 ms |
| Peak opacity | 0.5 |
| Blur | `stdDeviation` 4.5 |
| Expansion | ×1.28 |
| Stagger | 90 ms |

Timing is tuned to the **positive afterimage** (~0.5 s, same hue, dimmer), not the
negative one (complementary hue, 1–5 min). A `negative` mode ships in
`tokens.json` with a measured complement set, but it puts off-palette colour on
screen — treat it as an experiment, not the default.

**Why this is not an effect.** An afterimage is literally a memory trace:
photoreceptor fatigue leaves an image persisting after the stimulus is gone. That
is precisely Semon's 1904 engram — "the physical trace an experience leaves."
The mark demonstrates the brand's core concept **in the viewer's own visual
system** rather than illustrating it. Do not tune this into a generic glow.

Respect `prefers-reduced-motion`: rest the mark in its fired home state rather
than killing animation to zero, and skip afterimages entirely.

---

## 4. Colour

### Accents

| Token | Value | Node | Contrast on `--bg` |
|---|---|---|---|
| `--cyan` | `#22d3ee` | 1 | 10.59:1 |
| `--amber` | `#f0a050` | 2 | 8.98:1 |
| `--violet` | `#a78bfa` | 3 | 7.03:1 |
| `--emerald` | `#34d399` | 4 | 9.96:1 |

**Accents are positional, not semantic.** Cyan is always the first node fired,
emerald always the last, whatever grid positions the path uses. They encode
sequence. Never map them to status, category, or severity — use dedicated
semantic colours for that, kept outside the brand palette.

### Dark (primary)

| Token | Value | Role |
|---|---|---|
| `--bg` | `#0e0f14` | Ground. Near-black with a blue bias |
| `--surface` | `#15171d` | Raised panels, cards |
| `--hairline` | `rgba(255,255,255,0.08)` | Dividers, 1px borders |
| `--text` | `#f0f0f2` | Primary text — 16.8:1 |
| `--mid` | `rgba(255,255,255,0.62)` | Body, secondary — 7.7:1 |
| `--dim` | see `tokens.json` | Latent dots, micro-labels |

The ground is **not neutral black**. `#0e0f14` carries a blue bias that lets cyan
and violet sit into it while amber and emerald lift off it. The palette was chosen
against this ground and drifts on true black.

### Light

Site only. **Brand material and video stay dark.** Accents are unchanged but carry
far less weight on light and should not be relied on to structure a layout there.

| Token | Value |
|---|---|
| `--bg` | `#fafaf9` |
| `--surface` | `#ffffff` |
| `--text` | `#1a1a1a` |
| `--mid` | `rgba(0,0,0,0.64)` |
| `--dim` | `rgba(0,0,0,0.45)` |

---

## 5. Typography

Three faces, and a strong weight discipline: **the system runs light.** Weight 300
is the workhorse, 400 for emphasis, 200 and 100 for display. The eye should read
air, not ink.

| Role | Face | Weight | Treatment |
|---|---|---|---|
| Display | Outfit | 100–200 | Tight leading, negative tracking |
| Body | Outfit | 300 | 1.65 leading, ~68ch measure |
| Micro-label | Outfit | 400 | Uppercase, 2–3px tracking, 10–13px |
| Code / data | JetBrains Mono | 300–400 | Tabular numerals wherever digits align |
| Editorial | Literata | 300–400 | Long-form prose and quotation only |
| Mark | Outfit | **900** | Reserved — the four letters, nothing else |

**Weight 900 belongs to the mark.** That reservation is what makes the mark feel
like a different object from the page around it. Spend it elsewhere and the mark
loses its authority.

Weight history: 700 to 600 on the 2026-08-18 audit (the R's counter measured only
1.13× its own stem, argued to close under ink spread) to **900 at em 32** by eye.
The audit's concern was real but it reasoned about letters at em 25; with more
absolute room, 600 read visibly light. The cost is a higher floor — see §2.

---

## 6. Design language

How to derive smaller elements so they belong to this system rather than merely
sitting next to it. The mark's own logic supplies the rules.

### Principles

1. **Radius is circular or square, rarely between.** The mark is made of circles
   and straight bars. Use `999px` for pills and dots, `3px` for panels and inputs.
   Mid-range rounding (8–16px) reads as generic SaaS and fights the mark.
2. **Borders over fills.** Surfaces are separated by `--hairline`, not by boxes of
   colour. Depth comes from a one-step lift `--bg` to `--surface`, never shadow.
3. **No shadows, no glows, no gradients** — except the gradient *inside a bar*
   between two node colours, which is the one gradient the system owns.
4. **One accent per view.** A screen picks a single accent and stays with it.
   Four accents in one interface turns positional meaning into decoration.
5. **State is carried by opacity and weight**, not by hue shifts. Resting 0.38,
   active 0.88, exactly as the nodes behave.

### Components

| Element | Rule |
|---|---|
| **Button, primary** | Accent fill, `--bg` text, radius 3px, 400 weight, 0.5px tracking. Hover raises opacity, never changes hue |
| **Button, secondary** | `--hairline` border, `--text`, transparent fill. Hover fills to `--surface` |
| **Card / panel** | `--surface`, 1px `--hairline`, radius 3px, no shadow |
| **Input** | `--bg` fill, 1px `--hairline`, radius 3px. Focus swaps the border to the view's accent — no glow, no ring |
| **Chip / tag** | Pill (999px), `--surface`, `--mid` text, 11px, 400, 1.5px tracking |
| **Dot / status** | 7px circle — the resting node radius. Reuse the mark's own unit |
| **Divider** | 1px `--hairline`. Never a heavier rule |
| **Code** | JetBrains Mono 300, `--surface`, radius 3px |
| **Table** | Header 10.5px uppercase, tracking 1.6px, `--dim`. Rows separated by `--hairline` top borders only |

### Spacing

The mark's grid unit is 60 at viewBox 200 — 30% of its width. Interfaces use a
**4px base scale**: 4, 8, 12, 16, 24, 32, 48, 72, 96. Section rhythm is 72px
desktop, 48px mobile.

### Motion

Inherit the mark's easing rather than inventing new curves.

- Entrances and size changes: `cubic-bezier(0.4, 0, 0.2, 1)`, 300–600 ms
- Fades: `ease-in-out`, 300–400 ms
- Draw-on: `ease-out`, 500 ms
- Staggers: 150 ms for lists, 500 ms when nodes fire in sequence

Motion states what changed. Never animate purely for interest.

---

## 6b. Secondary graphic system

Every element in the mark is a **dot** or a **bar** on a **grid**. The secondary system
invents nothing beyond those three — which is why any composition built from them can
fire, hold and dissolve exactly as the mark does. A divider is not a line that happens
to animate; it is three nodes that can fire in sequence.

| Device | Is | Used for |
|---|---|---|
| **Dot** | the resting node, r=7 | list markers, status, separators |
| **Numbered dot** | a node that has **fired** — Outfit 900 knocked out of the disc | ordered steps |
| **Bar** | stroke 11, round cap, opacity 0.72, gradient between the accents it joins | dividers, rules, emphasis |
| **Path** | four nodes joined by three bars — the home path, flattened | section dividers, page breaks |
| **Orb** | a fired node carrying its complementary bloom | section markers, accent moments |
| **Ghost field** | 9 mm lattice of dots at ~9% opacity, breathing on an 18 s cycle | page and section grounds |
| **Grid rule** | the lattice line, 1px hairline | dividers |

**The test for any new element:** can it be built from a dot, a bar, or the grid? If
not, it does not belong to the system — and it will not animate with the rest of it.

Never a glyph bullet, never a dash, never a chevron.

## 7. Merchandise

Single-colour reproduction is the constraint that governs merch. Use the mono
assets — full-colour four-accent printing on fabric rarely holds.

| Item | Treatment |
|---|---|
| **T-shirt, dark** | `mark-mono-light.svg` left chest at 70 mm, or stacked lockup centred at 200 mm |
| **T-shirt, light** | `mark-mono-dark.svg`, same placements |
| **Hoodie** | Mark only, left chest 70 mm. Wordmark across the back at 260 mm, or nothing |
| **Cap** | Mark only, 55 mm, embroidered. Latent dots at 55 mm approach the minimum — drop to the reduced four-node form |
| **Mug** | Wrap the full-colour mark on white, or mono on black. Clear space still applies to the handle |
| **Sticker** | Die-cut to the mark's bounding box plus clear space. Full colour |
| **Tote / notebook** | Mono, single placement, no lockup |

Embroidery notes: minimum 55 mm for the full mark; below that the 7px latent dots
fall under thread gauge and fill in. Bars at stroke-width 11 scale to roughly
3 mm at 55 mm — at or just above most embroiderers' minimum.

Never: all-over prints of the mark, the mark as a repeating pattern, the mark
distorted around a curve, or accent-coloured garments matched to a node colour.

---

## 8. Video

Rules derived from production, not preference. Each is a defect we hit and fixed.

| Rule | Value | Why |
|---|---|---|
| Clip coverage | `n_terms × clip_duration >= audio_duration` | Below this, material ordering wraps and the back half desynchronises from the script |
| Slot granularity | ~4 s | A 60 s piece needs ~15 distinct visual slots |
| Tail budget | 1.5–2 s | Cut to exactly the narration and the picture ends mid-breath; on a looping platform that reads as broken |
| Closing shot | node / network | The mark condenses out of the last frame instead of replacing it |
| Music gain | 0.10 | Under narration, continuing through the end card |

- **Never crossfade narration.** Speech runs at full level to its last word; the
  picture transitions afterwards, during silence.
- **Music runs continuously through the end card** and fades only in the final 2 s.
- **Pin one track per campaign.** Randomised music destroys audio identity.
- **Tag stock material by what is in frame**, not by the narrative beat it serves.
  Concrete nouns resolve well; actions and abstractions do not.
- **No identifiable stock people.** They read as stock however well matched, and
  undercut a product sold on credibility to engineers.

---

## 8b. Export

Every variant ships as SVG **and** PNG at 64 / 128 / 256 / 512 / 1024 / 2048 px, in
transparent and on-ground forms, under `assets/export/`. SVG is the master; PNG is
generated from it, so the two cannot drift. Regenerate with:

```bash
python3 build_assets.py && python3 export_assets.py
```

## 9. Open questions

Recorded rather than guessed, so they can be closed deliberately.

| Question | Current state |
|---|---|
| Endorsed tagline | "One memory. Every agent. Yours." on site and video end card; positioning guidance elsewhere leads with "the memory layer for AI" |
| Video call to action | Domain only. Install command untested on an end card |
| Campaign music | Provisionally pinned, not chosen on merit |
| Literata's role | Loaded site-wide, used sparingly. Either commit or drop it |
| Light-theme accents | Unchanged from dark and under-tested at that ground |
| `--dim` contrast | See `$issues.dim-contrast` in `tokens.json` |
