veza/apps/web/docs/BRANDING.md
senke 33fcd7d1bd feat(branding): scaffold Logo component + Sumi icons + brand assets pipeline (Sprint 3)
Sprint 3 = production assets (logo, icons, hero, textures). Most deliverables
are physical artistic work (artist Renaud + Nikola scans). This commit lays
the CODE scaffold so assets drop in without friction when delivered.

New : apps/web/src/components/branding/
- Logo.tsx — single source of truth for Talas / Veza brand rendering.
  Replaces ad-hoc inline wordmarks (Sidebar/Navbar/Footer/landing each had
  their own VEZA <h2>). Variants: wordmark / symbol / lockup. Sizes xs..xl.
  Colors auto/ink/cyan/inverse. Optional tagline. Horizontal/vertical orient.
- assets/SymbolPlaceholder.tsx — geometric ink stroke + arc + dot, monochrome,
  currentColor inheritance, scalable. Mirrors charte §3.1 brief. Replaced by
  artist's hand-drawn mark in P0.1 of BRIEF_ARTISTE.
- Logo.stories.tsx — full Storybook coverage: variants, sizes, colors,
  orientation, Talas vs Veza, all-sizes ladder.
- index.ts — barrel exports.

New : apps/web/src/components/icons/sumi/
- Play.tsx — first calligraphic icon stub (programmatic approximation per
  charte §6.3). 9 more to come (Pause, Search, Profile, Chat, Upload,
  Settings, Home, Close, Volume).
- index.ts — barrel + commented TODO list per priority.
- Used via existing components/icons/SumiIcon.tsx wrapper which falls back to
  Lucide when no Sumi version exists.

Brand alignment of platform metadata :
- public/favicon.svg — Mizu cyan placeholder (#0098B5) replacing default
  vite.svg. Mirrors SymbolPlaceholder geometry.
- public/manifest.json — theme_color #1a1a1a -> #0098B5 (SUMI accent),
  background_color #ffffff -> #0D0D0F (charte §4.4 rule 1: no pure white).
- index.html — theme-color meta + msapplication-TileColor aligned to SUMI.
  Favicon link points to /favicon.svg.

New doc : apps/web/docs/BRANDING.md
- Architecture map of brand assets in apps/web.
- Logo component API + usage examples.
- Asset deliverables status table (P0/P1/P2 from brief artiste, all 🟡 placeholders).
- Naming convention for raw scans + processed SVGs.
- Step-by-step "how to integrate a delivered asset" for wordmark and Sumi icon.
- Brand color guard (ESLint rule pointer).

Build OK (vite 12.6s). Typecheck clean. No visual regression — Sidebar/Navbar
inline wordmarks intentionally NOT migrated yet (they use fontWeight 300 which
contradicts charte's Bold requirement; a per-screen migration call later).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 17:08:17 +02:00

6.1 KiB
Raw Blame History

Branding & assets pipeline — apps/web

Single source of truth for how Talas / Veza brand assets enter the codebase. Reference brand spec : CHARTE_GRAPHIQUE_TALAS.md.


Architecture

apps/web/
├── public/
│   ├── favicon.svg             # SVG favicon (Mizu cyan placeholder)
│   ├── icons/                  # PWA icons (PNG, 72x72 to 512x512)
│   ├── fonts/                  # Self-hosted woff2 (Space Grotesk, Inter, JetBrains Mono)
│   └── manifest.json           # PWA manifest (theme_color = #0098B5 SUMI accent)
└── src/
    ├── components/
    │   ├── branding/
    │   │   ├── Logo.tsx        # SOLE entry point for Talas / Veza wordmark + symbol
    │   │   ├── Logo.stories.tsx
    │   │   ├── assets/
    │   │   │   ├── SymbolPlaceholder.tsx  # Geometric placeholder, swap for hand-drawn
    │   │   │   ├── TalasWordmark.tsx      # (P0.1 artist deliverable — 3 variants)
    │   │   │   └── VezaWordmark.tsx       # (P1.1 artist deliverable — 1 variant)
    │   │   └── index.ts
    │   └── icons/
    │       ├── SumiIcon.tsx    # Wrapper : prefers hand-drawn, falls back to Lucide
    │       └── sumi/           # Hand-drawn calligraphic icons (10 prioritaires)
    │           ├── Play.tsx
    │           ├── Pause.tsx           (TODO)
    │           └── ...

Logo component

Always use <Logo /> instead of inline <h2>VEZA</h2> style markup.

import { Logo } from '@/components/branding';

// Default (wordmark, md, theme-aware color)
<Logo brand="veza" />

// Lockup with tagline
<Logo brand="veza" variant="lockup" size="lg" tagline="STREAMING" />

// Symbol only (favicon-style usage)
<Logo brand="talas" variant="symbol" size="sm" />

// Cyan accent
<Logo brand="veza" variant="lockup" color="cyan" />

API : see Logo.stories.tsx for all variants in Storybook.


Asset deliverables — current status

Per BRIEF_ARTISTE_IDENTITE_VISUELLE.md (artist Renaud, 15 avril 2026) and Sprint 3 :

Asset Priority Status Location
TALAS wordmark × 3 (propre, sauvage, vertical) P0.1 awaiting artist branding/assets/TalasWordmark.tsx (pending)
Hero image post-apo P0.2 awaiting artist public/hero/ (pending)
VEZA wordmark × 1 (tag fluide) P1.1 awaiting artist branding/assets/VezaWordmark.tsx (pending)
3-5 textures de liaison P1.2 awaiting artist public/textures/ (pending)
3 symboles iconiques (enso, onde, libre) P1.3 awaiting artist branding/assets/Symbol.tsx (pending)
Talas symbole (calligraphique) 🟡 placeholder branding/assets/SymbolPlaceholder.tsx
Favicon SVG 🟡 placeholder public/favicon.svg
10 Sumi icons (play/pause/search/...) 🟡 1/10 stubbed components/icons/sumi/
washi.png texture inline SVG (feTurbulence) src/index.css:456 (no external file)
Fonts (Space Grotesk + Inter + JetBrains Mono) self-hosted public/fonts/*.woff2
PWA icons (PNG, 9 sizes) 🟡 generic placeholders public/icons/icon-*.png

Naming convention

  • Wordmarks : {brand}_wordmark_{variant}.svg then exported as React component
    • Example : talas_wordmark_propre.svgTalasWordmarkPropre.tsx
  • Symbols : {brand}_symbol_{type}.svg
  • Hero / textures : {kind}_{number}.png (raw scans), processed to webp for prod
  • Always store source SVGs (vectorized) ; processed bitmaps in build

Format requirements (per BRIEF_ARTISTE §5)

  • Scan minimum 600 DPI (1200 if available). PNG/TIFF only — no JPG (bleeding edges on ink).
  • One artwork per file. Naming : talas_wordmark_sauvage_01.png etc.
  • No retouching before delivery — clean fond, niveaux, détourage handled in apps/web preprocessing.
  • Paper white (not cream) ; encre de Chine (not brown-tinted black) ; aquarelle limited to terreuse palette.

How to integrate a delivered asset

Wordmark (e.g. TALAS propre)

  1. Receive talas_wordmark_propre_01.png (scan 600+ DPI).

  2. Clean fond + isolate ink in Inkscape : File → Import → Select-by-color (white) → Delete → Trace bitmap.

  3. Export SVG with currentColor fills + transparent background.

  4. Save as apps/web/src/components/branding/assets/TalasWordmark.tsx :

    import type { SVGProps } from 'react';
    export default function TalasWordmark(props: SVGProps<SVGSVGElement>) {
      return (
        <svg viewBox="0 0 240 60" xmlns="http://www.w3.org/2000/svg" {...props}>
          {/* Pasted SVG paths here, fills set to currentColor */}
        </svg>
      );
    }
    
  5. Update Logo.tsx to use <TalasWordmark /> for brand='talas' instead of the text fallback. (Detect via prop or via fallback chain.)

  6. Storybook will show it automatically.

Sumi icon (e.g. Pause)

  1. Receive pause_01.png from artist.

  2. Vectorize manually in Inkscape (no auto-trace — preserves irregularity).

  3. Save as apps/web/src/components/icons/sumi/Pause.tsx.

  4. Add export to components/icons/sumi/index.ts.

  5. At call site :

    import { SumiIcon } from '@/components/icons/SumiIcon';
    import { PauseIcon } from '@/components/icons/sumi';
    import { Pause } from 'lucide-react';
    
    <SumiIcon sumi={PauseIcon} fallback={Pause} size={24} />
    

The SumiIcon wrapper handles the "use hand-drawn if available, else Lucide fallback" logic, so you can drop hand-drawn icons in progressively.


Brand color guard

ESLint rule (eslint.config.js no-restricted-syntax for hex literals) blocks new hardcoded colors. To fix a warning :

  • CSS context (JSX style/className/template literal) : use var(--sumi-*).
  • TS / canvas context : import { ColorVizIndigo } from '@veza/design-system/tokens-generated';.

Source of truth for all colors : packages/design-system/tokens/primitive/color.json.