.brand-lockup primitive: LI.FI (the parent brand) and Jumper (the consumer sibling brand — same design system and components, differentiated by theme, brand colour tokens, and Urbanist typography). Used wherever a sub-product needs its own canonical chrome while staying anchored to its parent brand.Brand lockup .brand-lockup
LI.FI mark + wordmark + optional sub-product label. Bare .brand-lockup is identity-only; add .brand-lockup--back on real navigation surfaces to opt into the chevron→back-arrow hover swap.
<!-- Real navigation surface — wrap in <a href> AND add the -->
<!-- .brand-lockup--back modifier so the chevron→back-arrow hover -->
<!-- swap fires. Catalog previews omit the modifier and stay static. -->
<a href="/" class="brand-lockup brand-lockup--back" aria-label="Back to lifi.fi">
<span class="brand-lockup__glyph">
<svg class="brand-lockup__glyph-idle"><!-- LI.FI mark --></svg>
<svg class="brand-lockup__glyph-hover"><!-- back arrow --></svg>
</span>
<svg class="brand-lockup__wordmark"><!-- LI.FI letters --></svg>
<span class="brand-lockup__label">Playground</span>
</a>
| Property | Value | Token |
|---|---|---|
| Glyph + wordmark height | 24px | var(--space-24) |
| Mark canonical viewBox | 0 0 40 48 | logos/lifi/lifi-mark.svg — never narrow below width 40; the corner curves paint to x≈38.628 (see the file header) |
| Stacked canonical viewBox | 0 0 32 48 | logos/lifi/lifi-lockup-stacked.svg — compact mark redraw, monochrome currentColor |
| Lockup gap (glyph ↔ wordmark) | 4px | var(--space-4) |
| Wordmark ↔ label gap | 2px | var(--space-2) |
| Label font | Figtree | Inherits from html |
| Label size | 16px | var(--text-body) |
| Label baseline nudge | translateY(0.5px) | Optical — typographic baselines match exactly, but Light-weight antialiasing + round-cap overshoot read ~1px low against the crisp vector wordmark; tuned at 6× zoom |
| Label weight | 300 | Light — quiet against the bold wordmark |
| Label tracking | 0 | var(--tracking-normal) |
| Label colour | muted ink | var(--text-muted) |
| Hover swap duration | 180ms ease | — |
| Class | Role | Notes |
|---|---|---|
| .brand-lockup | Wrapper | Identity-only by default. Use <a> for back-link semantics; <div> for static identity |
| .brand-lockup--back | Modifier — interactive back-link | Opt-in: enables the chevron→back-arrow hover swap. Apply only on real navigation surfaces (DS nav, product rails). Catalog previews omit this so they stay static. |
| .brand-lockup__glyph | Mark slot | 24×24 box; positions both glyph SVGs absolutely so the swap is layout-free |
| .brand-lockup__glyph-idle | Idle SVG | LI.FI chevron mark; visible by default |
| .brand-lockup__glyph-hover | Hover SVG | Back-arrow; cross-fades in on :hover only when the wrapper carries .brand-lockup--back |
| .brand-lockup__wordmark | "LI.FI" letters | SVG sibling of __glyph; never animates, always visible |
| .brand-lockup__label | Sub-product name | Optional. Hidden below 720px viewport via existing media query |
- One label per surface. Each LI.FI sub-product surface owns exactly one label string. Don't stack multiple labels (e.g. "Playground · Beta") — use a separate chip primitive for status modifiers.
- Wrap in
<a href>+ add.brand-lockup--backwhen it's an interactive back-link. The hover swap (chevron → back-arrow) reads as "click here to return to LI.FI" only on real navigation surfaces. Static identity (footer brand, marketing hero, catalog previews) uses bare.brand-lockup— no modifier, no swap, no implied interactivity. - Match the navbar's own logo via
display: none. When the lockup lives inside a sub-product chrome (rail, drawer, sidebar), hide the host page's.navbar-site__logoso the brand identity reads from one place per surface. - Never restyle the wordmark. No outlines, shadows, gradients, or font swaps — the LI.FI letters are a brand asset, not a styled text element.
- Sub-product label is mono uppercase. Same recipe across every sub-product so the family reads as a system. Don't introduce per-product label fonts or weights.
- Below 720px, the label hides. The mark + wordmark continue to identify the brand; sub-product context is implicit on small screens. Don't author override media queries for individual sub-products.
CSS: styles.css — search for .brand-lockup.
Consumers: playground.html (rail header), ds-nav.js (DS catalog navbar). Future LI.FI sub-products import the same primitive.
Tokens: var(--space-24), var(--space-4), var(--space-2), var(--text-body), var(--font-mono), var(--text-primary), var(--text-muted), var(--text-secondary).
Spec: design/components/imagery.md → ### Brand lockup
Jumper lockup .brand-lockup--jumper
Two-tone Jumper mark + wordmark + optional sub-product label. Fills ride --jumper-indigo / --jumper-purple so the lockup flips with the mode; the label renders in Urbanist.
<!-- Jumper variant — same slot anatomy as the LI.FI lockup. Add -->
<!-- .brand-lockup--jumper (sub-product label renders in Urbanist + -->
<!-- accent-2 purple). The SVG fills are token-driven so the mark -->
<!-- flips with the mode: var(--jumper-indigo) body + wordmark, -->
<!-- var(--jumper-purple) accent piece + label. Never bake the hex. -->
<a href="/" class="brand-lockup brand-lockup--jumper brand-lockup--back" aria-label="Back to jumper.xyz">
<span class="brand-lockup__glyph">
<svg class="brand-lockup__glyph-idle"><!-- Jumper mark · logos/jumper/jumper-mark.svg --></svg>
<svg class="brand-lockup__glyph-hover"><!-- back arrow --></svg>
</span>
<svg class="brand-lockup__wordmark" viewBox="29 0 89 25"><!-- JUMPER letters --></svg>
<span class="brand-lockup__label">Pass</span>
</a>
| Property | Value | Token |
|---|---|---|
| Glyph + wordmark height | 24px | var(--space-24) |
| Mark canonical viewBox | 0 0 24 25 | logos/jumper/jumper-mark.svg |
| Wordmark crop viewBox | 29 0 89 25 | Letters-only crop of jumper-lockup.svg (full-height box so letters sit at the lockup's proportions) |
| Stacked canonical viewBox | 0 0 45 44 | logos/jumper/jumper-lockup-stacked.svg |
| Body + wordmark fill | #31007A light · #653CA2 dark | var(--jumper-indigo) |
| Accent-piece fill | #8700B8 light · #B49BDA dark | var(--jumper-purple) |
| Label font | Urbanist | var(--font-jumper) |
| Label colour | accent 2 — #8700B8 light · #B49BDA dark | var(--jumper-purple) |
| Label size / weight | 16px · 300 | var(--text-body) · var(--fw-light) — shared with the LI.FI label recipe |
| Label baseline nudge | translateY(-0.25px) | Optical — JUMPER's wordmark baseline sits at 18/25 of its box vs LI.FI's 36/48; tuned at 6× zoom |
| Gaps (glyph↔wordmark · wordmark↔label) | 4px · 2px | var(--space-4) · var(--space-2) |
| Class / asset | Role | Notes |
|---|---|---|
| .brand-lockup--jumper | Brand variant modifier | Composes onto .brand-lockup. Owns three label deltas — typography (Figtree → Urbanist), colour (muted → accent 2 --jumper-purple), and its own optical baseline nudge; geometry, hover swap, and slot anatomy stay shared |
| .brand-lockup__glyph-idle | Jumper mark | Two-tone leaping-J; fills carry var(--jumper-indigo) / var(--jumper-purple) with light-mode hex fallbacks |
| .brand-lockup__wordmark | "JUMPER" letters | Path-based (no font dependency); viewBox 29 0 89 25 renders ~85px wide at the 24px lockup height |
| .brand-lockup__label | Sub-product name | Pass / Scan / Learn — renders in Urbanist + accent-2 purple via the modifier; uppercase via the shared label recipe |
| logos/jumper/ | Canonical asset dir | jumper-mark.svg · jumper-lockup.svg · jumper-lockup-stacked.svg — the source files every consumer copies from |
- Tokens, never literals. The mark's two tones are
var(--jumper-indigo)(body + wordmark) andvar(--jumper-purple)(accent piece) — mode-paired to Jumper's own published light/dark tokens. Baking#31007A/#8700B8into a consumer freezes the logo in light mode; the hex literals exist only asvar()fallbacks inside the asset files so<img>/downloaded copies stay brand-correct. - One shared primitive, one modifier. Jumper lockups compose
.brand-lockup--jumperonto the same slot anatomy as LI.FI. Don't fork a Jumper-specific lockup component — the modifier owns exactly three label deltas (Urbanist typography, accent-2 colour, optical baseline nudge), and everything else inherits. - Sub-product naming: wordmark + label. JumperPass / JumperScan / JumperLearn render as the JUMPER wordmark + a quiet sub-product label (Pass / Scan / Learn) — same pattern as LI.FI Playground. Don't typeset the compound name ("JumperPass") as a single wordmark.
- Mark crops come from the canonical files. Reach for
jumper-mark.svg(viewBox0 0 24 25) for the glyph alone andjumper-lockup-stacked.svgfor square slots — never crop the horizontal lockup's viewBox by hand. - Never restyle the wordmark. No outlines, shadows, gradients, or font swaps — the JUMPER letters are path-based brand assets, not styled text.
- Theme presets are a separate channel.
jumper-1/jumper-2in the Theme Composer re-theme SURFACES with Jumper accents; the logo tokens here are brand constants that don't move when a user composes a theme. Don't wire the logo fills to--accent-*.
Assets: logos/jumper/jumper-mark.svg · logos/jumper/jumper-lockup.svg · logos/jumper/jumper-lockup-stacked.svg.
CSS: styles.css — search .brand-lockup--jumper (modifier) and --jumper-indigo (brand tokens, dark in :root / light in [data-theme="light"]).
Export: shared.js → initBrandLockupExport() — per-brand geometry via the BRANDS map (data-lockup-brand="jumper").
Typography: var(--font-jumper) (Urbanist) — see Foundations → Typography.
Theme presets: presets.js → jumper-1 / jumper-2.
Spec: design/components/imagery.md → ### Brand lockup
LI.FI logo — usage requirements
All three variants. Clear space ½H, minimum sizes 16 / 20 / 48 px, single-ink monochrome — never accents, never gradients.
Three variants, picked by slot shape: the mark for avatars, favicons, and tight square slots; the horizontal lockup for headers, documents, and partner co-branding; the stacked lockup for app tiles, social cards, and tall square slots. Every composition rule below scales with H — the rendered logo height — so the system holds at any size.
Clear space — ½H on every side
Nothing enters the clear-space zone — no text, no icons, no other logos, no container edges. The zone is measured from the logo's bounding box and scales linearly with H.
Mark · H 48 → clear space 24
Horizontal · H 32 → clear space 16
Stacked · H 96 → clear space 48
Colour application — single ink, monochrome
The LI.FI logo carries no accent colours by design. One ink: black on light surfaces, white on dark. In-product it renders currentColor and follows --text-primary; externally it ships as black with white as the dark-surface alternative.
On light — black, single ink
On dark — white, single ink
Minimum sizes — legibility floors
Below the floor, switch variants: a horizontal lockup that must render under 20 px becomes the mark; a stacked lockup under 48 px becomes the mark or the horizontal lockup.
Mark · 16 px floor
Horizontal · 20 px floor
Stacked · 48 px floor
| Requirement | Value | Notes |
|---|---|---|
| Clear space | ½H · all four sides | H = rendered logo height; measured from the bounding box, scales linearly |
| Minimum size — mark | 16px tall | Below it, the notch detail closes up |
| Minimum size — horizontal lockup | 20px tall | Wordmark letters render ~10px — the legibility floor |
| Minimum size — stacked lockup | 48px tall | The small wordmark under the mark renders ~8.4px |
| Mark viewBox / aspect | 0 0 40 48 · 5:6 | lifi-mark.svg — never narrow below width 40 (corner curves paint to x≈38.628) |
| Horizontal viewBox / aspect | 0 0 132 48 · 11:4 | lifi-lockup.svg |
| Stacked viewBox / aspect | 0 0 32 48 · 2:3 | lifi-lockup-stacked.svg |
| Ink | single — black on light · white on dark | currentColor; in-product follows --text-primary |
- Single ink, always. Black on light, white on dark,
--text-primaryin-product. Never accent colours, never gradients, never two-tone — the LI.FI logo's monochrome restraint is its identity. - Respect the ½H clear space. No text, icons, other logos, or container edges inside the zone. When a slot can't honour it, the slot is too small — drop to a smaller variant rather than crowding.
- Ship the canonical files.
logos/lifi/is the source for all three variants. Never crop a lockup's viewBox down to the mark (the mark file exists for that) and never redraw — the mark's corner curves paint past intuition (x≈38.628 in the 40-wide box). - No transforms, no effects. Don't stretch, skew, rotate, outline, shadow, or glow. Scale uniformly only.
- Never typeset the wordmark. The LI.FI letters are paths, not a font — don't rebuild them in Figtree or anything else.
- On photography or busy surfaces, plate it. Place the logo on a solid plate (white or near-black) sized to the clear-space zone rather than directly on imagery.
Assets: logos/lifi/lifi-mark.svg · logos/lifi/lifi-lockup.svg · logos/lifi/lifi-lockup-stacked.svg — downloadable from the Brand Lockup card above.
In-product rendering: .brand-lockup (styles.css).
Spec: design/components/imagery.md → ### Brand lockup → Logo usage guidelines
Jumper logo — usage requirements
All three variants. Clear space ½H, minimum sizes 16 / 20 / 48 px, two-tone pair flips by mode — never swapped, never flattened.
Same composition system as LI.FI — clear space ½H, the same minimum-size floors, the same variant-by-slot logic. What differs is colour: the Jumper logo is two-tone by design, and the pair is token-driven so it flips with the surface's mode.
Clear space — ½H on every side
Same rule as LI.FI: nothing enters the zone, and it scales linearly with the rendered height.
Mark · H 48 → clear space 24
Horizontal · H 32 → clear space 16
Stacked · H 96 → clear space 48
Colour application — the two-tone pair flips together
The accent spark (the small top dash) always carries accent 2 (--jumper-purple); the body and wordmark always carry accent 1 (--jumper-indigo). The pair flips together by mode — light pair on light surfaces, dark pair on dark. Never swap the two tones, never mix pairs across modes, and never flatten to one colour without brand review.
Light pair — Indigo #31007A · Vivid Purple #8700B8
Dark pair — Purple #653CA2 · Lavender #B49BDA
--jumper-purple
Body + wordmark · --jumper-indigo
Minimum sizes — legibility floors
Same floors and the same variant-switching rule as LI.FI: below the floor, drop to the next-smaller variant rather than shrinking past legibility.
Mark · 16 px floor
Horizontal · 20 px floor
Stacked · 48 px floor
| Requirement | Value | Notes |
|---|---|---|
| Clear space | ½H · all four sides | H = rendered logo height; measured from the bounding box, scales linearly |
| Minimum size — mark | 16px tall | Below it, the spark separates poorly from the body |
| Minimum size — horizontal lockup | 20px tall | Wordmark letters render ~9.6px — the legibility floor |
| Minimum size — stacked lockup | 48px tall | The small wordmark under the mark renders ~6.5px |
| Mark viewBox / aspect | 0 0 24 25 · ~1:1 | jumper-mark.svg |
| Horizontal viewBox / aspect | 0 0 118 25 · ~19:4 | jumper-lockup.svg |
| Stacked viewBox / aspect | 0 0 45 44 · ~1:1 | jumper-lockup-stacked.svg |
| Accent spark | #8700B8 light · #B49BDA dark | var(--jumper-purple) |
| Body + wordmark | #31007A light · #653CA2 dark | var(--jumper-indigo) |
- The two-tone pair IS the logo. Spark =
--jumper-purple, body + wordmark =--jumper-indigo. Never swap the tones, and never flatten to a single colour without brand review. - The pair flips together by mode. Light pair (#31007A + #8700B8) on light surfaces, dark pair (#653CA2 + #B49BDA) on dark. Never mix across pairs — a light indigo body with a dark lavender spark is a broken logo.
- Tokens in code, literals only in standalone files. Inline usage rides
var(--jumper-indigo)/var(--jumper-purple)so the mode flip is automatic; the asset files carry the light-mode literals asvar()fallbacks for<img>and downloads. - Don't recolour to surface accents. The Theme Composer's
--accent-*tokens re-theme SURFACES; the logo tokens are brand constants. A Jumper logo in LI.FI blue (or any composed accent) is never correct. - Respect the ½H clear space and the size floors — same system as LI.FI above.
- No transforms, no effects, no typeset wordmark. Scale uniformly; the JUMPER letters are paths, not Urbanist text.
- Ship the canonical files from
logos/jumper/; never hand-crop the horizontal lockup's viewBox to get a mark.
Assets: logos/jumper/jumper-mark.svg · logos/jumper/jumper-lockup.svg · logos/jumper/jumper-lockup-stacked.svg — downloadable from the Brand Lockup card above.
Brand tokens: styles.css — --jumper-indigo / --jumper-purple (dark in :root, light in [data-theme="light"]).
In-product rendering: .brand-lockup--jumper (styles.css).
Spec: design/components/imagery.md → ### Brand lockup → Logo usage guidelines
scripts/iso/*.mjs on a shared engine (the 2:1 dimetric projection + wireframe primitives), white-on-ink so the lines read on any page theme while the brand palette still retints them. The animated scenes loop in place. The brand-guide "in motion" cards are the motion showcase; this section is the asset library. Method: the iso-illustration skill.Isometric assets scripts/iso/
Outline-only isometric wireframes on ink — generated from scripts/iso/*.mjs on the shared engine, so every asset renders at one consistent edge weight and retints with the brand. Animated scenes loop in place.
24 tiles · isometric assets generated from scripts/iso/*.mjs — devices and emblems, the composable objects, and full scenes that assemble objects + real marks into one projection. Each in wireframe (outline, ink-on-paper) and, where built, surface (filled, brand-accent) mode. They follow light / dark and re-tint with the Theme Composer; animated scenes loop in place. Click any tile to open it in the lightbox — navigate with the arrows, ←/→ keys, or scroll.
Composable objects
Reusable building blocks (a layer above the primitives, in scripts/iso/objects.mjs) for assembling full scenes. Each renders in both engine modes — wireframe (ink outline) + surface (accent fill) — and is avatar-ready: a face slot (the empty ring) swaps for any token / chain / dex / wallet mark.
Scenes
Full compositions (the top tier, in scripts/iso/scene.mjs) — the objects + real chain / token / dex marks assembled into one shared projection, joined by connection lines with lit data-flow dots riding them on a loop. Both engine modes; multi-avatar marks are id-namespaced per instance so their gradients never collide.
Never hand-author the SVG — generate it from the scene, then embed the output inline (inline so it reads --surface-page + animates):
# generate a bare SVG from any scene
node scripts/iso/mac-studio.mjs back > out.svg
node scripts/iso/macbook.mjs > out.svg
# standalone preview harness (dark panel) to iterate
node scripts/iso/mac-studio.mjs html > scripts/iso/mac-studio-preview.html
<!-- embed: a fixed-ink tile that pins light mode -->
<figure class="ds-iso-tile" data-theme="light">
<svg class="bb-iso" viewBox="…">…</svg>
</figure>
Every scene composes the shared engine scripts/iso/engine.mjs:
C— the white-on-ink palette (edge20% ·faint13% ·mark48% ·lit85%), every colour acolor-mixover--surface-page.SW— the stroke-weight ladder (hair1.1 ·edge1.6 ·bold2.4), rendered withvector-effect:non-scaling-strokeso edges read at one consistent width across every scene regardless of its viewBox scale.createIsoKit— the 2:1 dimetric projection +slab()/keycap()for hardware scenes; flat scenes (coin, swap) use the core only.autoFrame+wrapSvg— a square viewBox from the content bbox + the SVG wrapper (which injects the non-scaling-stroke rule).
Method, contracts and the per-scene worked examples live in the iso-illustration skill.
- Generate, never hand-edit the SVG. Change the scene generator, regenerate, re-embed.
- Author every stroke from
SW+ colour fromCso a new scene is edge-consistent with the family by construction. - Embed inline, on a
data-theme="light"ink tile. An<img>can neither read--surface-pagenor animate; the light-pin keeps the white-on-ink look on any theme. - Outline-only. The one fill is the active/moving element (a typed keystroke, the flow pip).
- The brand-guide "in motion" cards are the motion showcase; this is the asset library.
viewBox="0 0 24 24", stroke-width="2", stroke-linecap="round", stroke-linejoin="round" baseline. Source SVGs live in /icons/.Iconography
Lucide icon library at stroke-width="1.5" on Marketing surfaces, 2.0 on Product. Plated containers for chain / token logos.
119 icons · Lucide outline set, rendered at stroke-width="1.5" for Marketing surfaces and 2.0 for Product. Every icon uses currentColor, so it inherits text colour and palette retints automatically.
<!-- Icons live in /icons/ as bare-stroke SVGs. Inline them so currentColor + size work. -->
<svg viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12h14"/>
<path d="M12 5v14"/>
</svg>
/* Size tokens: 14 / 16 / 18 / 20 / 24. Scale via width+height attrs or font-size on parent. */
| Class / size | Use |
|---|---|
| .avatar | Base — 40×40 default; consumes --avatar-size via fallback so cluster wrappers can drive size |
| .avatar--xs | 24×24 — table cells, dense lists, chip slots |
| .avatar--sm | 32×32 — compact list-item leads, secondary identity rows |
| .avatar--lg | 48×48 — card thumbnails, stat tiles, "integrated with N chains" stacks |
| .avatar--xl | 64×64 — hero rows, feature cards, partner showcase |
| .avatar--2xl | 96×96 — marketing heroes, brand-asset-library hero tiles |
| .avatar--square | 4px radius — keeps source geometry intact |
| .avatar--rounded | 25% radius — chips, badges, tiers |
| .avatar--circle | 50% radius — disk; "latest integration" avatars |
- Lucide for UI glyphs.
stroke-width="1.5"on Marketing/Docs surfaces;2.0on dense Product UI where the line needs more presence. - Source from
/icons/first. Every icon you reach for must already exist in the project's library at/icons/<name>.svg. If it doesn't: stop and ask whether to add it to the library from the official source (lucide.dev for UI glyphs, the brand's own asset repo for logos). Don't paste a one-off SVG straight into a feature file — the library is the canonical surface, and ad-hoc copies drift over time. - Use the exact path from the library file. No truncated decimals (
4.93 → 4.9), no Feather-era variants (e.g. the old moonM21 12.79A9 9 0 1 1 11.21 3…was replaced upstream byM20.985 12.486a9 9 0 1 1-9.473-9.472…). Copy the path verbatim from the corresponding SVG. - One action ↔ one icon. Every recurring affordance — edit, save, delete, copy, more, back — uses the same Lucide glyph everywhere it appears. Before introducing a new icon for an action, grep for the existing one (
theme-card-edit,copy-button, etc.) and reuse it. Picking a similar-but-different Lucide glyph (pencilvspencil-line,savevssave-all) for the same action is the most common drift in this codebase. - Plated logos for chains / tokens / partners. Source SVG inside
.avatar— the wrapper handles the plate. Avatar SVGs live in/avatars/{chains,tokens,dexs,bridges,wallets,exchanges,payments,social,lifi}/; same library-first rule applies (verify the file exists before referencing it). - Pick the shape by context. Square for tables, rounded for chips, circle for avatars.
- Don't mix Lucide with brand glyphs in one row. Lucide is chrome; brand glyphs are content.
.avatar in any size or shape. Sibling libraries: Partner Logos for wordmark+mark lockups, Portraits for persona / team photography.Avatars library /avatars/
Plated 32×32 brand-mark SVGs — chains, tokens, bridges, DEXs, wallets, payments, social, LI.FI sub-products. Rendered at 40px via .avatar.
211 avatars across 10 categories · pre-plated 32×32 SVG (Solana tokens are temporary PNG) · rendered at 40px through .avatar. Every brand background lives inside the file, so no wrapper tint is needed. Wordmark+mark lockups live in Partner Logos; persona / team photography lives in Portraits.
Chains · 80
Network logos — kebab-case full name.
Tokens · 31
Currency / asset glyphs — lowercase ticker.
Solana tokens · 5
Solana-ecosystem token marks — lowercase ticker. Circular coin art (.avatar--circle).
Temporary PNG placeholders pending SVG. The rest of the library is pre-plated SVG; these break that contract until brand-vector marks land, at which point they swap in place under the same filenames.
DEXs · 34
DEX brand marks — kebab-case full name.
Bridges · 29
Cross-chain bridges — kebab-case full name; version suffix when relevant (across-v3).
Wallets · 9
Wallet apps — kebab-case full name.
Exchanges · 3
Centralized exchange marks — kebab-case full name.
Payments · 3
Card / payments-product marks — kebab-case full name.
Social · 12
Social platform marks — currently numbered alts; rename target.
LI.FI · 5
LI.FI’s own brand marks — wordmark, mark, and product sub-brands.
<!-- Plated avatars (32 × 32 source). Six sizes via .avatar--xs/--sm/--lg/--xl/--2xl (default = 40px, no modifier). -->
<span class="avatar">
<img src="/avatars/chains/ethereum.svg" alt="Ethereum">
</span>
<!-- Stacked / overlapping -->
<span class="avatar-stack avatar-stack--tight">
<span class="avatar">…</span>
<span class="avatar">…</span>
</span>
| Folder | Count | Naming | Examples |
|---|---|---|---|
| /avatars/chains/ | 80 | kebab-case full name | ethereum, arbitrum, base, optimism, polygon, solana |
| /avatars/tokens/ | 31 | lowercase ticker | eth, usdc, usdt, dai, steth |
| /avatars/solana/ | 5 | lowercase ticker · temporary PNG | bonk, jto, jup, ray, wif |
| /avatars/bridges/ | 29 | kebab-case full name | across-v3, stargate-v2-fast-mode, hop, celer-cbridge, circle-cctp |
| /avatars/dexs/ | 34 | kebab-case full name | uniswap, curve, 1inch, paraswap |
| /avatars/wallets/ | 9 | kebab-case full name | metamask, phantom, coinbase-wallet, walletconnect, ledger, rabby |
| /avatars/exchanges/ | 3 | kebab-case full name | binance, coinbase, okx |
| /avatars/payments/ | 3 | kebab-case full name | kast, mastercard, visa |
| /avatars/social/ | 12 | numeric placeholder | alt-1 … alt-12 (rename target) |
| /avatars/lifi/ | 5 | product name (no lifi- prefix) | lifi, collector, composer, pioneer, wrapper |
Tokens deviate from the kebab-case convention because tokens are canonically referenced by ticker in trading / wallet UI (eth.svg, not ethereum-token.svg).
- 32×32 SVG, pre-plated. Use the library's plate, don't add your own — the source already has the right padding for
.avatarwrappers. - Default render = 40px — no modifier needed (was 32px before April 2026; the source viewBox is unchanged, the wrapper just scales).
- Avatar ≠ partner logo. If the asset is a wordmark with brand typography, it belongs in
logos/partners/with a-dark/-lightpair, rendered through.ds-doc-partner-logo— not here. - Add via the library, never inline. Reference by path (
../avatars/chains/foo.svg); never paste an SVG inline. - When importing a new avatar, prompt the user to add a cell to this grid in the catalog. The library is not auto-synced.
- Compress on import. Source SVGs from official brand pages are often 50KB+; SVGO + manual cleanup brings them under 4KB.
.ds-doc-partner-logo. Sibling libraries: Avatars for icon-only brand identifiers, Portraits for persona / team photography.Partner logo library /logos/partners/
Full brand wordmarks for partner attribution — varied aspect ratio, ships -dark + -light pairs, theme-swapped via CSS. Rendered through .ds-doc-partner-logo.
29 partners · 58 SVGs (-dark + -light pairs) · rendered at 32px through .ds-doc-partner-logo. The active variant follows the page theme — flip the theme toggle in the header to swap.
<span class="ds-doc-partner-logo ds-doc-partner-logo--md" role="img" aria-label="MetaMask">
<img class="ds-doc-partner-logo__dark" src="logos/partners/metamask-dark.svg" alt="">
<img class="ds-doc-partner-logo__light" src="logos/partners/metamask-light.svg" alt="">
</span>
Both <img> tags ship in source; CSS swaps display on [data-theme="light"]. Use aria-label for the brand name and leave individual <img alt> empty (the wrapper carries semantics).
| Class | Role | Notes |
|---|---|---|
| .ds-doc-partner-logo | Wrapper, height-constrained | Inline-flex; default 32px high (--md) |
| .ds-doc-partner-logo--sm / --md / --lg | Size modifiers | 24 / 32 / 40 px high — width follows aspect |
| .ds-doc-partner-logo__dark | Dark-theme variant | Visible by default; hidden on light |
| .ds-doc-partner-logo__light | Light-theme variant | Hidden by default; visible on light |
| .ds-doc-partner-logo-grid | Catalog grid | auto-fill, min cell 220px |
| .ds-doc-partner-logo-cell | Catalog cell | Plate + figcaption around one wordmark |
- Wordmarks only. If a partner has only a square mark, use
.avatarinstead — partner-logo expects a wide-aspect logo with brand typography baked in. - Always ship a
-dark+-lightpair. Single-variant logos break the theme swap; if a partner only has one variant, render it through.avatarinstead. - Use
aria-labelon the wrapper, notalton imgs. The<span>carries the role + label; the inner imgs are decorative (alt=""). - Don't tint or recolour. Partner logos are sacrosanct — no opacity overrides, no greyscale unless the wider section is
.logo-cloud--mono. - Compress on import. SVG wordmarks frequently include unused fonts as paths; SVGO + manual cleanup brings most under 6KB.
.avatar (which handles size, shape, and optional plates) via <img srcset> against the size ladder. Full procedure in design.md §05 → People asset library. Sibling libraries: Avatars for icon-only brand identifiers, Partner Logos for wordmark+mark lockups.People library /portraits/
Portrait photos across three governance buckets — personas (free use), team (sign-off), external (consent).
5 portraits across 2 active buckets (Personas · Team) · transparent PNGs · master 1024px + 96 / 256 derivatives per slug. external/ bucket ships empty (.gitkeep) and populates as consented photos land. Different governance per bucket — see the Rules tab.
Personas · 4
Fictional archetypes — Kim (Shrimp · first-time DeFi), Finn (Fish · active trader), Dale (Whale · ETH maxi), Mabel (Stablecoin Maxi). Reusable in product demos, design exploration, and marketing scenes without consent friction.
Team · 1
Real LI.FI team — internal sign-off required before any external surface. Vilen Rodeski (Director of Design) is the first entry; the bucket grows as additional teammates complete sign-off.
Plate options · 9
Three accent solids (primary / secondary / tertiary), two neutrals (ink / paper), three brand gradients (linear / rich / radial). The same portrait reads differently on each ground — pick by surface context, not personality. Inline style="--avatar-bg: …" remains the escape hatch for one-off plates.
Shape options · 3
The same shape ladder as every other avatar — .avatar--square (4 px), .avatar--rounded (25%), .avatar--circle (50%). Default reach for portraits is circle, but rounded reads as a brand tile on feature cards and pricing tiers, and square sits cleanly inside table cells.
<!-- Persona portrait — circular, brand-gradient plate revealed through alpha. -->
<img class="avatar avatar--lg avatar--circle avatar--plate-brand"
src="../portraits/personas/kim-96.png"
srcset="../portraits/personas/kim-96.png 96w,
../portraits/personas/kim-256.png 256w,
../portraits/personas/kim.png 1024w"
sizes="(max-width: 600px) 48px, 96px"
alt="Kim — Shrimp persona">
<!-- Plate alternatives: -->
<!-- Accent solids — .avatar--plate-primary / -secondary / -tertiary -->
<!-- Neutrals — .avatar--plate-ink / -paper -->
<!-- Brand gradients — .avatar--plate-brand / -brand-rich / -brand-radial -->
<!-- Strip plate — .avatar--plate-none -->
<!-- Shape ladder — .avatar--square / -rounded / -circle -->
<!-- Inline custom — style="--avatar-bg: oklch(60% 0.18 200);" -->
- Personas — no consent constraint. Reusable on public surfaces, decks, demos. The four current archetypes (Kim · Finn · Dale · Mabel) are fictional and were generated for the system.
- Team — internal sign-off required before any external surface (marketing, decks shared outside the company, public site). Add the master at
portraits/team/<firstname>-<lastname>.png. - External — explicit per-person consent, often with expiration. Treat the bucket as "ask before each new use" — terms may have lapsed since the file was committed.
- Never reuse a real-person photo for a fictional persona, or vice versa. The folder boundary is also a semantic boundary.
- Don't apply tints or background plates inside the PNG. Photos are documentary — if a layout needs the person on a coloured ground, build the ground via
.avatar--plate-*or inline--avatar-bg, never bake it.