Ce document est la specification technique complete de SUMI v3. Il definit les regles, contraintes et tokens a implementer pour obtenir une UI singuliere, vivante et econome en ressources. Toute modification de l'UI doit etre conforme a ce document.
Direction artistique : lavis japonais interactif (sumi-e numerique). Voir 05_EXPERIENCE_UTILISATEUR/DIRECTION_ARTISTIQUE_TALAS pour la philosophie complete.
| SUMI v2 (actuel) | SUMI v3 (cible) |
|---|---|
| Palette indigo froide (#7c9dd6) | Palette cyan (#0098B5) — touche de couleur unique dans un lavis monochrome |
| Surfaces plates (flat design) | Surfaces = couches d'encre diluee sur papier washi |
| Themes statiques (dark/light) | Theme circadien (le lavis suit le soleil — papier chaud/froid/inverse) |
| Interface figee | Interface qui se patine (le papier vieillit, l'encre s'oxyde) |
| Animations generiques | Animations avec le poids de l'eau (goutte/trait/lavis/vague/maree) |
| Icones standard | Icones = gestes calligraphiques dessines a la main |
| Player = barre en bas | Player = suzuri (pierre a encre) — objet le plus dense de l'interface |
| Performance non budgetee | Budget strict par metrique |
| Bordures nettes (border CSS) | Bords diffus comme l'encre dans l'eau (box-shadow tres diffus) |
Ce qui est conserve :
--sumi-* pour toutes les variablesLe cyan (#0098B5) est la seule couleur d'accent. Dans un lavis traditionnel, une seule touche de couleur suffit a tout transformer. Le cyan est cette touche. Il evoque l'eau — l'element qui transporte l'encre, qui donne vie au lavis. Il contraste avec le noir/blanc ambiant comme un eclat de ciel dans un paysage monochrome.
/* SUMI v3 — Pigment primaire (cyan) */
--sumi-accent: #0098B5;
--sumi-accent-hover: #00B4D8;
--sumi-accent-active: #007A94;
--sumi-accent-muted: rgba(0, 152, 181, 0.15);
--sumi-accent-subtle: rgba(0, 152, 181, 0.08);
--sumi-accent-emphasis: #006B7F;
/* Focus ring — cyan diffus dans l'eau */
--sumi-border-focus: rgba(0, 152, 181, 0.50);
--sumi-shadow-glow: 0 0 0 3px rgba(0, 152, 181, 0.25);
--sumi-shadow-glow-lg: 0 0 20px rgba(0, 152, 181, 0.12);
Les couleurs fonctionnelles sont des pigments dilues dans beaucoup d'eau. Elles apparaissent rarement : en lignes fines, en micro-points, en halos subtils. Jamais en aplats. Elles ne rivalisent jamais avec le cyan.
--sumi-success: rgba(90, 140, 100, 0.60); /* Vert sauge dilue */
--sumi-error: rgba(180, 80, 70, 0.55); /* Rouge brique dilue */
--sumi-warning: rgba(190, 150, 60, 0.55); /* Ambre dilue */
--sumi-info: #0098B5; /* Le cyan lui-meme */
Regles des couleurs fonctionnelles :
Le fond est du papier. Jamais une surface lisse. Jamais du blanc pur. Jamais du noir pur. Le papier a une texture, une chaleur, une vie.
/* Jour (papier washi clair) */
--sumi-bg-void: #EBE5DD; /* Washi vieilli — le papier le plus expose */
--sumi-bg-base: #F2EDE6; /* Fond principal — papier washi */
--sumi-bg-raised: #F7F3EC; /* Surfaces posees sur le papier */
--sumi-bg-overlay: #FBF8F2; /* Dropdowns, overlays */
--sumi-bg-hover: rgba(26, 26, 30, 0.06); /* Encre tres diluee */
--sumi-bg-active: rgba(26, 26, 30, 0.10); /* Encre legerement plus dense */
/* Nuit (lavis inverse — papier sombre, encre claire) */
--sumi-bg-void: #09090B; /* Noir d'encre profond */
--sumi-bg-base: #0D0D0F; /* Fond principal — papier sombre */
--sumi-bg-raised: #141416; /* Surfaces : couche d'encre legerement plus claire */
--sumi-bg-overlay: #1A1A1E; /* Overlays */
--sumi-bg-hover: rgba(232, 227, 219, 0.06); /* Encre claire diluee */
--sumi-bg-active: rgba(232, 227, 219, 0.10); /* Encre claire plus dense */
Le texte est de l'encre posee sur du papier. Noir profond le jour, blanc creme la nuit. Le texte secondaire est de l'encre diluee.
/* Jour */
--sumi-text-primary: #1A1A1E; /* Encre sumi — dense mais pas pur */
--sumi-text-secondary: #9A958D; /* Encre diluee — gris chaud */
--sumi-text-tertiary: #B5B0A8; /* Encre tres diluee — s'efface comme un lavis dilue */
--sumi-text-link: #0098B5; /* Liens = accent cyan */
/* Nuit (inversion) */
--sumi-text-primary: #E8E3DB; /* Encre claire sur papier sombre */
--sumi-text-secondary: #9A958D; /* Encre diluee — reste gris chaud */
--sumi-text-tertiary: #706B63; /* Encre tres diluee en mode nuit */
--sumi-text-link: #006B7F; /* Cyan profond la nuit */
Les surfaces ne sont jamais parfaitement lisses. Le fond porte la texture du papier washi — grain subtil, fibres visibles, surface vivante. Les elements poses dessus sont des couches d'encre diluee a differentes concentrations.
Un seul fichier image : washi.png (512x512, ~8 Ko)
Photo d'un vrai papier washi, desaturee, grain visible. Applique sur le body en pseudo-element.
/* Pseudo-element sur le body — texture washi globale */
body::after {
content: '';
position: fixed;
inset: 0;
pointer-events: none;
z-index: var(--sumi-z-max);
background-image: url('/washi.png');
background-repeat: repeat;
opacity: var(--sumi-washi-opacity, 0.04);
mix-blend-mode: soft-light;
}
/* Variable de controle */
:root {
--sumi-washi-opacity: 0.04; /* Subtil — a peine perceptible */
}
/* Desactive en mode eco ou reduced-motion */
@media (prefers-reduced-motion: reduce) {
body::after { display: none; }
}
[data-eco="true"] body::after { display: none; }
Cout en performance : ~8 Ko au chargement, 0 impact en runtime (image statique,
GPU-composited via position: fixed). Negligeable.
Les surfaces elevees sont des couches d'encre diluee posees sur le papier. Pas de box-shadow traditionnelle — des diffusions douces, comme l'encre qui s'etend dans du papier mouille.
/* Les cartes sont des voiles d'encre poses sur le washi */
.sumi-card {
background: rgba(26, 26, 30, 0.04);
backdrop-filter: blur(8px);
/* Pas de border — un bord diffus d'encre */
box-shadow: 0 0 8px rgba(26, 26, 30, 0.05);
border: none;
}
/* Overlays — encre plus concentree */
.sumi-overlay {
background: rgba(26, 26, 30, 0.08);
backdrop-filter: blur(16px);
box-shadow: 0 0 16px rgba(26, 26, 30, 0.08);
border: none;
}
/* Modales — couche la plus dense */
.sumi-modal {
background: rgba(26, 26, 30, 0.15);
backdrop-filter: blur(24px);
box-shadow: 0 0 24px rgba(26, 26, 30, 0.10);
border: none;
}
| Elevation | Opacite encre | Blur du backdrop | Effet |
|---|---|---|---|
| Fond (papier) | 0% | — | Le papier washi brut |
| Surface (carte) | 4-8% | 8px | Un voile d'encre tres leger |
| Overlay (dropdown) | 8-12% | 16px | Une couche plus dense |
| Modale | 12-20% | 24px | Une zone nettement marquee |
| Player (suzuri) | 20-30% | 32px | L'element le plus "encre" — le plus present |
Les bordures ne sont pas des lignes CSS nettes. Elles sont des bords diffus d'encre, comme le contour d'une tache d'eau sur du papier.
/* MAL — bordure nette, mecanique */
border: 1px solid rgba(0, 0, 0, 0.1);
/* BIEN — bord diffus d'encre */
box-shadow: 0 0 6px rgba(26, 26, 30, 0.06);
border: none;
Regle : jamais de border visible. Toujours un box-shadow diffus
(spread 0, blur 4-8px, opacite 3-8%).
La "temperature" du papier change avec l'heure, comme la lumiere naturelle sur un rouleau de papier pose pres d'une fenetre. Le matin, le papier est chaud. Le jour, il est neutre. Le soir, il se rechauffe. La nuit, le lavis s'inverse : papier sombre, encre claire, cyan profond.
| Phase | Heures | Ambiance | Modification |
|---|---|---|---|
| Aube | 05h-08h | Papier rose/chaud, encre douce | Fonds legerement plus chauds, cyan tire vers le teal |
| Jour | 08h-17h | Papier neutre, contraste maximal | Palette standard — cyan vif |
| Crepuscule | 17h-20h | Papier qui se rechauffe, encre dense | Fonds plus chauds, cyan plus profond |
| Nuit | 20h-05h | Lavis inverse | Papier sombre (#0D0D0F), encre claire (#E8E3DB), cyan profond (#006B7F) |
// circadian.ts — calcule les ajustements de palette
interface CircadianShift {
bgWarmth: number; // -5 to +5 (degres hue shift sur les fonds)
accentWarmth: number; // -3 to +3 (degres hue shift sur l'accent)
brightness: number; // 0.95 to 1.05 (multiplicateur de luminosite)
contrast: number; // 0.97 to 1.0 (multiplicateur de contraste)
}
function getCircadianShift(hour: number): CircadianShift {
if (hour >= 5 && hour < 8) {
// Aube — papier plus chaud, encre plus douce
return { bgWarmth: 3, accentWarmth: 2, brightness: 1.02, contrast: 0.98 };
}
if (hour >= 8 && hour < 17) {
// Jour — neutre, contraste maximal, cyan vif
return { bgWarmth: 0, accentWarmth: 0, brightness: 1.0, contrast: 1.0 };
}
if (hour >= 17 && hour < 20) {
// Crepuscule — papier qui se rechauffe, encre plus dense
return { bgWarmth: 4, accentWarmth: 3, brightness: 0.98, contrast: 0.99 };
}
// Nuit — le lavis s'inverse, cyan s'approfondit
return { bgWarmth: 1, accentWarmth: -1, brightness: 0.95, contrast: 0.97 };
}
// Dans ThemeProvider, au montage + toutes les 30 minutes
function applyCircadianShift() {
const hour = new Date().getHours();
const shift = getCircadianShift(hour);
// Applique les shifts via des custom properties sur :root
document.documentElement.style.setProperty(
'--sumi-circadian-warmth', `${shift.bgWarmth}deg`
);
document.documentElement.style.setProperty(
'--sumi-circadian-brightness', `${shift.brightness}`
);
}
// Recalcul toutes les 30 min (pas besoin de plus frequent)
setInterval(applyCircadianShift, 30 * 60 * 1000);
/* Les fonds utilisent un filtre CSS plutot que de recalculer les couleurs */
:root {
--sumi-circadian-warmth: 0deg;
--sumi-circadian-brightness: 1;
}
/* Applique sur le conteneur principal, pas sur chaque element */
#app {
filter:
hue-rotate(var(--sumi-circadian-warmth))
brightness(var(--sumi-circadian-brightness));
transition: filter 300s linear; /* Transition de 5 min, imperceptible */
}
Avec le temps et l'usage, l'interface se patine comme un rouleau ancien. Le papier vieillit. L'encre s'oxyde et gagne en profondeur. Le grain du washi devient plus prononce. Le cyan prend des nuances plus profondes.
:root {
/* Calculees au login, basees sur le profil utilisateur */
--sumi-patina-level: 0; /* 0-4, entier */
--sumi-patina-warmth: 0; /* 0-10, degres de hue shift additionnel */
--sumi-patina-washi: 0.04; /* 0.04-0.08, opacite de la texture washi */
--sumi-patina-depth: 0; /* 0-3, diffusion d'encre additionnelle */
--sumi-patina-texture: none; /* none | subtle | rich | deep */
}
interface UserPatinaData {
accountAgeDays: number;
totalPlayTimeHours: number;
totalUploads: number;
totalMessages: number;
totalExchanges: number;
}
function calculatePatina(data: UserPatinaData): PatinaTokens {
// Score composite (0-100)
const ageScore = Math.min(data.accountAgeDays / 365, 1) * 25;
const playScore = Math.min(data.totalPlayTimeHours / 500, 1) * 25;
const createScore = Math.min(data.totalUploads / 20, 1) * 25;
const socialScore = Math.min(
(data.totalMessages + data.totalExchanges * 5) / 200, 1
) * 25;
const score = ageScore + playScore + createScore + socialScore;
// Niveau discret (0-4)
let level = 0;
if (score >= 15) level = 1; // Rode
if (score >= 35) level = 2; // Vecu
if (score >= 60) level = 3; // Patine
if (score >= 85) level = 4; // Heritage
return {
level,
warmth: level * 2.5, // 0, 2.5, 5, 7.5, 10
washi: 0.04 + (level * 0.01), // 0.04, 0.05, 0.06, 0.07, 0.08
depth: level * 0.75, // 0, 0.75, 1.5, 2.25, 3
texture: ['none', 'subtle', 'subtle', 'rich', 'deep'][level],
};
}
| Niveau | Texture washi | Chaleur | Diffusion encre | Effet visuel |
|---|---|---|---|---|
| 0 — Neuf | 0.04 | Aucune | Standard | Papier frais, encre nette |
| 1 — Rode | 0.05 | +2.5 hue | Legerement plus diffuse | Papier qui commence a jaunir |
| 2 — Vecu | 0.06 | +5 hue | Notablement plus riche | Fibres du washi plus visibles, encre plus chaude |
| 3 — Patine | 0.07 | +7.5 hue | Diffusion prononcee | Papier ancien, encre oxydee aux reflets bruns |
| 4 — Heritage | 0.08 | +10 hue | Profonde et chaleureuse | Rouleau ancien — texture riche, encre patinee, cyan profond |
/* Applique via data-attribute sur html */
[data-patina="1"] { --sumi-washi-opacity: 0.05; }
[data-patina="2"] { --sumi-washi-opacity: 0.06; }
[data-patina="3"] {
--sumi-washi-opacity: 0.07;
/* Bords d'encre legerement plus diffus — l'encre a eu le temps de s'oxyder */
--sumi-border-default: 0 0 8px rgba(26, 26, 30, 0.08);
}
[data-patina="4"] {
--sumi-washi-opacity: 0.08;
--sumi-border-default: 0 0 10px rgba(26, 26, 30, 0.12);
--sumi-shadow-sm: 0 2px 8px rgba(26, 26, 30, 0.10), 0 0 4px rgba(0, 152, 181, 0.06);
}
/* La patine se combine avec le circadien */
/* hue-rotate du circadien + hue-rotate de la patine = chaleur cumulee */
#app {
filter:
hue-rotate(calc(var(--sumi-circadian-warmth) + var(--sumi-patina-warmth, 0deg)))
brightness(var(--sumi-circadian-brightness));
}
Chaque element de l'UI a le poids de ce qu'il represente dans le lavis. Les elements legers bougent comme des gouttes d'encre. Les elements lourds bougent comme des vagues. L'eau est la metaphore universelle du mouvement.
| Masse | Elements | Metaphore lavis | Duree | Easing |
|---|---|---|---|---|
| Goutte | Tooltips, badges, toggles | Goutte d'encre qui tombe | 100ms | ease-out |
| Trait | Boutons, icones, liens | Trait de pinceau rapide | 150ms | ease-out avec rebond leger |
| Lavis | Cards, dropdowns, tabs | Encre qui s'etend dans l'eau | 250ms | cubic-bezier(0.25, 0.8, 0.25, 1) |
| Vague | Modales, sidebar, panneaux | Vague lente sur papier mouille | 350ms | cubic-bezier(0.16, 1, 0.3, 1) |
| Maree | Navigation de page, player | Le mouvement de fond de l'ocean | 450ms | cubic-bezier(0.33, 1, 0.68, 1) |
:root {
/* Durees par masse */
--sumi-motion-goutte: 100ms;
--sumi-motion-trait: 150ms;
--sumi-motion-lavis: 250ms;
--sumi-motion-vague: 350ms;
--sumi-motion-maree: 450ms;
/* Easings par masse */
--sumi-ease-goutte: cubic-bezier(0.25, 0.1, 0.25, 1);
--sumi-ease-trait: cubic-bezier(0.33, 1, 0.68, 1);
--sumi-ease-lavis: cubic-bezier(0.25, 0.8, 0.25, 1);
--sumi-ease-vague: cubic-bezier(0.16, 1, 0.3, 1);
--sumi-ease-maree: cubic-bezier(0.33, 1, 0.68, 1);
--sumi-ease-rebond: cubic-bezier(0.34, 1.56, 0.64, 1); /* Pour les gouttes/traits */
}
Jamais plus de 2 animations simultanees a l'ecran. Si un troisieme element doit s'animer, il attend que le premier termine. Implemente via un compteur CSS ou un gestionnaire JS leger.
/* La page entrante apparait par couches — comme un lavis qui se revele */
.page-enter {
opacity: 0;
transform: translateY(6px);
}
.page-enter-active {
opacity: 1;
transform: translateY(0);
transition:
opacity var(--sumi-motion-lavis) var(--sumi-ease-trait),
transform var(--sumi-motion-lavis) var(--sumi-ease-vague);
}
/* La page sortante se dissout — comme l'encre qui seche */
.page-exit {
opacity: 1;
}
.page-exit-active {
opacity: 0;
transition: opacity 150ms ease-out;
}
Les hover states font "s'etendre" l'element legerement, comme une goutte d'eau qui s'elargit sur le papier.
.sumi-interactive:hover {
transform: scale(1.01);
box-shadow: 0 0 12px rgba(26, 26, 30, 0.08);
transition:
transform var(--sumi-motion-trait) var(--sumi-ease-trait),
box-shadow var(--sumi-motion-trait) var(--sumi-ease-trait);
}
| Metrique | Budget | Actuel (SUMI v2) | Methode de mesure |
|---|---|---|---|
| Bundle JS initial (gzip) | < 120 Ko | ~150 Ko | vite build --report |
| Bundle CSS total (gzip) | < 15 Ko | ? | Idem |
| First Contentful Paint | < 1.2s | < 1.5s | Lighthouse |
| Largest Contentful Paint | < 2.0s | ? | Lighthouse |
| Time to Interactive | < 1.8s | < 2s | Lighthouse |
| Cumulative Layout Shift | < 0.05 | ? | Lighthouse |
| Total Blocking Time | < 150ms | ? | Lighthouse |
| Requetes au chargement initial | <= 5 | ? | Network tab |
| Polices chargees | <= 2 fichiers | 3-4 | Network tab |
| Images texture washi | <= 10 Ko total | 0 | Taille des assets |
| Animations simultanees max | 2 | Illimite | Audit visuel |
requestAnimationFrame actifs au repos |
0 | ? | Performance tab |
| Memoire JS heap (idle) | < 30 Mo | ? | Chrome DevTools |
Polices :
woff2 uniquementfont-display: swap obligatoire<head>Code splitting :
// Chaque page est un chunk separe
const Library = lazy(() => import('./pages/Library'));
const Discover = lazy(() => import('./pages/Discover'));
const Profile = lazy(() => import('./pages/Profile'));
const Settings = lazy(() => import('./pages/Settings'));
// Le player est dans le bundle initial (toujours visible)
Images :
loading="lazy" sur toutes les images hors viewportsrcset avec 3 tailles (320w, 640w, 1280w)Mode eco :
[data-eco="true"] {
/* Desactive les textures et animations */
body::after { display: none; } /* texture washi */
* { animation-duration: 0ms !important; }
#app { filter: none; } /* circadien + patine */
}
Prefetch intelligent :
<link rel="prefetch"> et non preload (priorite basse)Les icones SUMI v3 sont des gestes dessines — comme des caracteres calligraphiques simplifies. Elles ne sont pas des SVG generes par ordinateur. L'irregularite du trace est volontaire et preservee.
| Contrainte | Valeur |
|---|---|
| Format | SVG inline (pas de sprite, pas de font icon) |
| Taille de reference | 24x24 viewBox |
| Epaisseur de trait | 2px, variable (plus epaisse au debut du geste, plus fine a la fin) |
| Style | Stroke only (pas de fill), sauf exceptions |
| Couleur | currentColor (herite du texte parent) |
| Nombre max d'icones | 30 (pas plus — chaque icone est dessinee specifiquement) |
| Lignes | Irreguliere comme un vrai trait de pinceau (pas de Bezier parfaites) |
| Coins | Mix organique (pas uniformement arrondis) |
| Fonction | Metaphore | Description du geste |
|---|---|---|
| Play | Trait de pinceau diagonal | Un triangle forme par un seul trait rapide |
| Pause | Deux colonnes d'encre | Deux traits verticaux paralleles |
| Recherche | Enso (cercle zen) | Un cercle ouvert — non ferme, comme un enso |
| Profil | Capsule de micro | Forme ovale avec un trait de base |
| Chat / Messages | Onde sonore | Trois arcs concentriques |
| Upload | Trait ascendant | Un trait qui monte avec une goutte au sommet |
| Settings | Ensui (roue) | Cercle avec trait directionnel |
| Home | Montagne | Triangle inverse — symbole de montagne minimaliste |
| Notifications | Point d'encre | Cercle avec une onde de diffusion |
| Like / Favori | Trait croise | Deux traits qui se rencontrent en pointe |
| Volume | Ondes | Arc de cercle avec des ondes de diffusion |
| Menu | Trois traits | Trois traits horizontaux d'epaisseur variable |
| Close | Croix de pinceau | Deux traits croises d'un seul geste |
| Download | Trait descendant | Un trait qui descend vers une ligne de base |
| Share | Traces | Trois points relies par des traits de pinceau |
| Filter | Entonnoir de traits | Deux traits convergents vers le bas |
| Expand | Triangle ouvert | Symbole d'amplification — triangle de pinceau |
Dessiner les icones a la main (papier ou tablette), puis vectoriser dans Inkscape. L'irregularite du trace est volontaire et ne doit pas etre "corrigee" par l'outil de vectorisation.
Les icones sont stockees comme composants React SVG individuels dans
apps/web/src/components/icons/.
Le player est la pierre a encre (suzuri) de l'interface — l'objet le plus lourd, le plus present, le plus ancre. C'est la surface la plus "encree", la plus opaque, la plus dense. Ce n'est pas une barre generique en bas de page. C'est le coeur de l'experience.
| Contrainte | Valeur |
|---|---|
| Position | Bas de page, pleine largeur, toujours visible |
| Hauteur collapsed | 80px (--sumi-player-height) |
| Hauteur expanded | Jusqu'a 60vh (vue immersive — le lavis s'intensifie) |
| Waveform | Traits de pinceau horizontaux — le son EST l'encre |
| Controle volume | Trait vertical avec un point (goutte de pinceau) — pas un slider classique |
| Patine | Le suzuri est l'element qui se patine le plus vite et le plus visiblement |
| Adaptabilite | Le player prend les couleurs de l'artiste en cours d'ecoute |
| Animation au repos | Micro-oscillation du VU-metre (respiration) — CSS uniquement |
| Transition expand/collapse | --sumi-motion-vague + --sumi-ease-vague |
| Touch | Swipe up pour expand, swipe down pour collapse |
La waveform est pre-calculee cote serveur (tableau de 200 valeurs d'amplitude par morceau). Les barres ne sont pas rectangulaires — elles ont des bords arrondis et une opacite variable, comme des traits d'encre poses cote a cote.
.waveform-bar {
width: 2px;
margin: 0 1px;
background: var(--sumi-accent);
border-radius: 50%; /* Bords arrondis comme un trait de pinceau */
transition: height var(--sumi-motion-goutte) var(--sumi-ease-goutte);
}
.waveform-bar.played {
opacity: 1; /* Encre dense — la partie jouee */
}
.waveform-bar.unplayed {
opacity: 0.25; /* Lavis dilue — la partie a jouer */
}
Pas de canvas WebGL, pas de Three.js, pas de librairie audio-visualizer. 200 divs CSS = leger et suffisant.
Le volume est un trait vertical avec un point — comme un trait de pinceau interrompu par une goutte. Implementation :
<line>) avec un cercle (<circle>) positionne dessus<input type="range"> pour screen readers (visuellement cache)Quand le player est en mode expanded (vue immersive) :
Le mode eco est active :
prefers-reduced-motion: reduceSave-Data: on (header HTTP)navigator.getBattery() si disponible)| Fonctionnalite | Etat en mode eco |
|---|---|
| Texture washi | Desactivee |
| Circadien | Desactive (palette statique) |
| Patine | Desactivee (palette standard) |
| Animations | Reduites a 0ms |
| Waveform player | Barre de progression simple |
| Controle volume | Slider lineaire classique |
| Prefetch | Desactive |
| Images pochettes | Taille reduite (160x160 max) |
| Diffusions d'encre (box-shadow) | Desactivees |
| Backdrop-filter (blur) | Desactive |
Le mode eco ne change PAS :
L'app reste complete et utilisable. Elle perd juste sa texture — comme un lavis sur papier lisse au lieu de papier washi.
Quand l'utilisateur navigue sur le profil d'un artiste ou ecoute un de ses morceaux, l'interface s'adapte aux couleurs choisies par l'artiste.
Chaque artiste peut definir :
/* Stocke dans le profil artiste, charge avec les donnees du profil */
--artist-hue: 220; /* Teinte principale (0-360) */
--artist-saturation: 0.6; /* Saturation (0-1) */
--artist-lightness: 0.5; /* Luminosite (0-1) */
Quand un profil artiste est affiche ou qu'un morceau est en cours de lecture :
/* Le player et la page profil utilisent la couleur artiste */
.artist-context {
--sumi-accent: hsl(
var(--artist-hue),
calc(var(--artist-saturation) * 100%),
calc(var(--artist-lightness) * 100%)
);
}
Les autres elements (navigation, sidebar) restent en cyan standard. Seuls le player (suzuri) et la zone de contenu s'adaptent.
Cyan partout. L'accent est toujours cyan (#0098B5), sauf dans un contexte artiste. Pas d'autre couleur primaire. Le cyan est la goutte de pigment dans l'eau noire — rare et precieux.
Texture washi toujours. Sauf en mode eco. Opacite max 0.08. Le fond n'est jamais une surface lisse.
2 animations max. Jamais 3 elements qui bougent en meme temps.
Pas de blanc pur (#FFFFFF). Le blanc le plus clair est #F2EDE6 (papier washi). Le blanc pur n'existe pas dans un lavis — le papier a toujours une teinte.
Pas de noir pur (#000000). Le noir le plus profond est #0D0D0F (noir d'encre). Le noir pur est plat et sans vie — l'encre sumi a toujours de la profondeur.
Pas d'icone generique. Chaque icone est un geste calligraphique dessine specifiquement. Si une icone n'existe pas dans le set, elle n'est pas utilisee.
Le suzuri (player) est sacre. C'est l'element le plus soigne, le plus teste, le plus patine. Ne jamais le traiter comme un composant secondaire.
Rien n'est lineaire. Pas de transition: all 0.3s linear. Toute animation
a un easing organique — le mouvement de l'eau, pas d'un mecanisme.
Le mode eco doit etre beau aussi. L'app sans texture/animation/circadien doit rester coherente et agreable. C'est le lavis sur papier lisse — sobre mais pas pauvre.
Accessible d'abord. Chaque decision esthetique doit passer le test WCAG AA (4.5:1 pour le texte, 3:1 pour les grands elements). Si l'esthetique et l'accessibilite sont en conflit, l'accessibilite gagne.
Pas de bordures nettes. Jamais de border: 1px solid. Les bords sont
des diffusions d'encre — box-shadow diffus, toujours.
Le vide est un choix. L'espace negatif (ma) n'est pas du padding vide. C'est le papier qui respire entre les traits.
| Tache | Priorite | Complexite | Impact |
|---|---|---|---|
| Remplacer la palette indigo par cyan (#0098B5) | 1 | Faible | Fondamental |
| Ajouter la texture washi (washi.png + pseudo-element) | 1 | Faible | Texture immediate |
| Adapter les fonds (papier washi jour/nuit) | 1 | Faible | Ambiance |
| Remplacer les border par des box-shadow diffus | 1 | Moyenne | Langage visuel |
| Implementer les couches d'encre (backdrop-filter + opacites) | 1 | Moyenne | Profondeur |
| Renommer les tokens de mouvement (goutte/trait/lavis/vague/maree) | 1 | Faible | Coherence |
| Implementer les couleurs fonctionnelles pastel diffuse | 1 | Faible | Etats |
| Dessiner les 10 icones prioritaires (gestes calligraphiques) | 2 | Moyenne | Identite |
| Implementer le circadien (ThemeProvider + inversion nuit) | 2 | Moyenne | Vie |
| Refaire le player en suzuri (waveform pinceau + volume trait) | 2 | Elevee | Coeur de l'UX |
| Implementer la patine (niveau 0-2 d'abord) | 3 | Moyenne | Singularite |
| Ajouter le mode eco | 3 | Faible | Ethique |
| Implementer les couleurs artistes | 3 | Moyenne | Personnalisation |
| Patine niveaux 3-4 (encre oxydee, rouleau ancien) | 4 | Moyenne | Profondeur |
| Micro-mouvements du papier de fond (ondulation CSS) | 4 | Faible | Vie subtile |
| Variantes de texture washi pour la patine (2-3 fichiers) | 4 | Faible | Richesse |