Que fait drawn-notebook-ui ?
name: drawn-notebook-ui description: > Un système de design complet et un guide d'implémentation pour reproduire l'esthétique « Drawn Notebook » — un langage UI éditorial, artisanal et discret, initialement conçu pour le portfolio personnel d'Askar. Couvre de manière exhaustive chaque token, composant, animation et motif d'interaction, pour les deux plateformes Flutter (Dart) et Web (HTML/CSS/JS), en modes clair et sombre. Utilisez ce skill dès que l'utilisateur souhaite construire, adapter ou étendre ce langage visuel spécifique dans n'importe quel contexte.
Aperçu
Le Drawn Notebook n'est pas une bibliothèque de composants. C'est un langage de design — une philosophie cohérente à laquelle chaque pixel, chaque épaisseur de trait, chaque rythme d'espacement et chaque courbe de timing d'animation obéit. Son principe directeur est que l'interface doit ressembler à un carnet de croquis vivant : de l'encre dessinée sur du papier crème, des passages révélés lentement au fil du défilement, des fils de navigation qui traversent la page comme un voyage physique. Rien n'est bruyant. Rien n'est décoratif pour lui-même. L'UI gagne chaque élément visuel en l'ancrant dans le sens.
Ce skill est une référence précise et complète. Lors de l'implémentation de cette UI, suivez chaque section dans l'ordre. Ne sautez pas les définitions de tokens — chaque espacement, couleur et valeur de mouvement est porteur. Ne sautez pas la section sur le mode sombre — les deux thèmes sont des citoyens de première classe égaux et doivent être simultanément corrects en tout temps.
Section 1 — Philosophie de Design
1.1 Principes Fondamentaux
Confiance silencieuse, pas minimalisme pour lui-même. Le design est sobre, mais chaque élément qui reste est intentionnel. L'espace vide n'est pas de la paresse — c'est la page qui respire. L'œil de l'utilisateur est guidé par la composition, le poids et le mouvement, et non par la saturation des couleurs ou les fioritures décoratives.
Esthétique dessinée à la main sans skeuomorphisme littéral. L'UI fait référence à l'art du dessin — des épaisseurs de trait fines, une typographie éditoriale serif, des textures de grain de papier, des illustrations SVG rendues comme des dessins au trait — mais elle ne prétend pas être du papier. C'est une surface numérique qui respecte la tactilité de l'artisanat analogique sans l'imiter maladroitement.
Chaque section est un chapitre. La page est un défilement continu, et chaque section donne l'impression de tourner la page d'un carnet. Les arrière-plans des sections passent subtilement de neutres chauds à d'autres. Un fil doré continu (le SVG de la ligne de voyage) les relie visuellement.
Le mouvement est une narration, pas un divertissement. Les animations révèlent le contenu comme une main écrit des mots — apparaissant de bas en haut, s'estompant doucement, traçant des chemins SVG. Les durées sont lentes selon les standards modernes (1.2s–2s pour les révélations). C'est intentionnel. La rapidité implique le bruit. La lenteur implique le savoir-faire.
Éviter les schémas d'IA générique. Les motifs suivants sont explicitement interdits : arrière-plans de héros en dégradé avec des transitions violet-rose, grilles de cartes avec des hauteurs et des rayons de coins identiques, états de survol qui brillent au néon, coins arrondis surdimensionnés (> 14px sur la plupart des éléments), barres de compétences colorées avec des pourcentages, frises chronologiques avec des puces et des dates en gras, et toute utilisation d'émoji comme décoration.
Section 2 — Tokens de Design
2.1 Palette de Couleurs — Mode Clair (Carnet de Jour)
Chaque couleur en mode clair est un neutre chaud dérivé du papier, de la crème et de l'encre naturelle. Il y a une seule famille d'accent : or/terre cuite, allant d'un ambre discret à une brique chaude.
/* Mode Clair (appliqué à :root) */
--cream: #F7F5F0; /* Fond de page — surface principale */
--sage: #EEF3ED; /* Fond de la section À propos — le gris-vert le plus clair */
--parchment: #F1ECE3; /* Fond des sections Expérience + CV */
--warm-white: #FAF8F5; /* Fond de la section Compétences — la surface la plus claire */
--linen: #F3EFE8; /* Fond de la section Projets */
--sage-tint: #EFF3EE; /* Fond de la section Apprentissage */
--charcoal: #1A1A1A; /* Texte principal, traits SVG, bordures */
--soft-black: #2C2C2C; /* Texte secondaire, étiquettes fortes */
--warm-grey: #8A8580; /* Étiquettes atténuées, horodatages, légendes */
--light-grey: #C5BFB8; /* Invitation au défilement, séparateurs décoratifs */
--terracotta: #B87A5A; /* États de survol, puces, waypoints actifs */
--indigo: #6B6EA0; /* Réservé — non utilisé dans les motifs principaux */
--gold: #C4956A; /* Accent principal — ligne de voyage, icônes de compétences, chips */
--gold-dim: rgba(196, 149, 106, 0.3); /* Or doux pour les ombres, bordures */
--blush: #F0EBE5; /* Fond des chips/badges au survol */
--sage-dark: #8B9E8B; /* Teinte de séparation des bordures de section */
2.2 Palette de Couleurs — Mode Sombre (Carnet de Nuit)
Le mode sombre n'est pas une simple inversion. Les arrière-plans passent de crèmes chaudes à des noirs chauds profonds — une qualité presque encrée. Les couleurs d'accent s'éclaircissent légèrement pour maintenir la lisibilité sur les surfaces sombres.
/* Mode Sombre (appliqué à :root[data-theme="dark"]) */
--cream: #141210; /* Fond de page — noir chaud profond */
--sage: #171816; /* Fond de la section À propos */
--parchment: #1A1815; /* Fond des sections Expérience + CV */
--warm-white: #1E1B18; /* Fond de la section Compétences */
--linen: #181614; /* Fond de la section Projets */
--sage-tint: #161815; /* Fond de la section Apprentissage */
--charcoal: #EDE8E1; /* Texte principal — blanc cassé chaud */
--soft-black: #D8D2C8; /* Texte secondaire */
--warm-grey: #9E978F; /* Étiquettes atténuées */
--light-grey: #38342E; /* Séparateurs décoratifs */
--terracotta: #D98A62; /* Accent de survol — légèrement plus vif qu'en mode clair */
--indigo: #8C8FB8;
--gold: #D4A373; /* Accent principal — légèrement plus chaud qu'en mode clair */
--gold-dim: rgba(212, 163, 115, 0.3);
--blush: #241E1A;
--sage-dark: #9EAF9E;
/* Tokens de surface */
--card-glass: rgba(30, 27, 24, 0.72);
--card-glass-hover: rgba(42, 38, 34, 0.95);
--card-item-bg: rgba(24, 21, 19, 0.78);
--card-item-hover: rgba(38, 34, 30, 0.96);
--card-border: rgba(212, 163, 115, 0.22);
--card-border-hover: rgba(212, 163, 115, 0.48);
--card-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
--card-shadow-hover: 0 6px 20px rgba(0, 0, 0, 0.45);
--card-inset: inset 0 1px 0 rgba(255, 255, 255, 0.05);
--card-inset-hover: inset 0 1px 0 rgba(255, 255, 255, 0.08);
--badge-bg: rgba(24, 21, 19, 0.88);
--grain-opacity: 0.022; /* Plus faible en sombre pour éviter le aspect boueux */
2.3 Palette de Couleurs — Tokens de Surface Mode Clair
/* Tokens de surface Mode Clair */
--card-glass: rgba(255, 255, 255, 0.65);
--card-glass-hover: #ffffff;
--card-item-bg: rgba(247, 245, 240, 0.8);
--card-item-hover: rgba(255, 255, 255, 0.98);
--card-border: rgba(196, 149, 106, 0.22);
--card-border-hover: rgba(196, 149, 106, 0.45);
--card-shadow: 0 4px 16px rgba(26, 26, 26, 0.04);
--card-shadow-hover: 0 6px 20px rgba(196, 149, 106, 0.12);
--card-inset: inset 0 1px 0 rgba(255, 255, 255, 0.9);
--card-inset-hover: inset 0 1px 0 rgba(255, 255, 255, 0.95);
--badge-bg: rgba(247, 245, 240, 0.82);
--grain-opacity: 0.035;
2.4 Changement de Thème — Implémentation Sans Flash
La détection du thème doit s'exécuter de manière synchrone dans <head> avant le rendu de la page pour éviter un flash du mauvais thème (FOUT). C'est une exigence d'implémentation critique :
<head>
<!-- DOIT être le premier script dans <head>, avant toute balise de feuille de style -->
<script>
(function () {
try {
var stored = localStorage.getItem('color-scheme');
var prefersDark = window.matchMedia &&
window.matchMedia('(prefers-color-scheme: dark)').matches;
var theme = (stored === 'dark' || (!stored && prefersDark)) ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', theme);
var meta = document.querySelector('meta[name="color-scheme"]');
if (meta && (stored === 'dark' || stored === 'light')) meta.content = stored;
var themeColor = document.querySelector('meta[name="theme-color"]');
if (themeColor) themeColor.content = theme === 'dark' ? '#141210' : '#F8F4F0';
} catch (e) {}
})();
</script>
</head>
Dans Flutter/Dart, utilisez ThemeMode.system par défaut, avec une persistance via SharedPreferences. La clé est color-scheme, la valeur est 'dark' ou 'light'.
2.5 Tokens Typographiques
--font-serif: 'Cormorant Garamond', 'Georgia', serif;
--font-sans: 'Inter', 'Helvetica Neue', sans-serif;
Cormorant Garamond est non négociable pour la voix éditoriale de ce design. Il est chargé aux poids 300, 400, 500, 600, avec des variantes italiques pour 300 et 400. Il est utilisé pour tous les titres, les titres de sections, le nom du héros, les chips, les étiquettes de rail, les messages de waypoint, et partout où une qualité « écrite » est nécessaire. Il ne doit jamais être utilisé à des poids supérieurs à 600 — ce n'est pas une police de caractères en gras.
Inter est le compagnon fonctionnel. Il est utilisé pour les légendes, les balises de compétences, les horodatages, les kickers en majuscules et le corps du texte dans des contextes d'information dense. Chargez les poids 300, 400, 500 uniquement.
/* Importation Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;1,300;1,400&family=Inter:wght@300;400;500&display=swap');
2.6 Tokens d'Espacement
Tous les espacements sont fluides en utilisant clamp(). N'utilisez pas de valeurs de pixels dures pour le padding des sections ou les contraintes de largeur du contenu.
--section-pad: clamp(80px, 12vh, 160px); /* Padding vertical pour les sections principales */
--content-max: 800px; /* Colonne de prose étroite */
--content-wide: 1100px; /* Mise en page large pour les grilles */
--side-pad: clamp(24px, 5vw, 80px); /* Marges horizontales de la page */
2.7 Tokens d'Animation
--ease-out: cubic-bezier(0.25, 0.46, 0.45, 0.94); /* Ease-out général */
--ease-smooth: cubic-bezier(0.4, 0, 0.2, 1); /* Lissage de type Material */
--duration-slow: 1.2s; /* Animations de révélation */
--duration-med: 0.8s; /* Transitions moyennes */
--duration-fast: 0.4s; /* Micro-interactions rapides */
Section 3 — Fondations Globales
3.1 Réinitialisation CSS et Base
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
scroll-behavior: smooth;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
background-color: var(--cream);
color: var(--charcoal);
font-family: var(--font-sans);
font-weight: 300;
line-height: 1.7;
overflow-x: hidden;
position: relative;
}
3.2 Sélection de Texte
La surbrillance de sélection est un lavis doré doux — elle reflète la palette d'accent sans être agressive :
::selection {
background: rgba(196, 149, 106, 0.2);
color: var(--charcoal);
}
::-moz-selection {
background: rgba(196, 149, 106, 0.2);
color: var(--charcoal);
}
3.3 Adaptation des Traits SVG
Tous les SVGs en ligne utilisent des traits hex codés en dur (#1A1A1A, #2C2C2C) de la palette du mode clair. Pour les adapter au mode sombre sans toucher au balisage SVG, utilisez un sélecteur de remplacement d'attribut CSS :
svg [stroke="#1A1A1A"], svg [stroke="#1a1a1a"] { stroke: var(--charcoal); }
svg [fill="#1A1A1A"], svg [fill="#1a1a1a"] { fill: var(--charcoal); }
svg [stroke="#2C2C2C"], svg [stroke="#2c2c2c"] { stroke: var(--soft-black); }
svg [fill="#2C2C2C"], svg [fill="#2c2c2c"] { fill: var(--soft-black); }
svg text[fill="#1A1A1A"] { fill: var(--charcoal); }
svg text[fill="#8A8580"] { fill: var(--warm-grey); }
Les accents dorés (#C4956A) dans les SVGs ne sont INTENTIONNELLEMENT PAS remplacés. L'accent doré est une couleur de référence fixe dans les deux thèmes ; en mode sombre, le token --gold s'éclaircit à #D4A373, mais l'or SVG en ligne n'a pas besoin de remappage car le contraste sur les fonds sombres est toujours acceptable.
3.4 Transition de Thème Fluide
Appliquez une transition coordonnée à chaque surface qui change entre les thèmes. Cela empêche les sauts de couleur brusques :
body, section,
.about, .experience, .resume-section, .skills, .projects, .learning, .closing,
.exp-card, .exp-item, .skill-cell, .compact-card, .compact-card__icon,
.about__point, .about__visual-card, .about__chip, .closing__link,
.journey-waypoint__message, .rail-node__label, .resume-modal__panel,
.resume-modal__header {
transition:
background-color 0.35s var(--ease-out),
color 0.35s var(--ease-out),
border-color 0.35s var(--ease-out);
}
/* Toujours respecter la préférence de mouvement de l'utilisateur */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { transition: none !important; }
}
Section 4 — Superposition de Grain de Papier
Une texture de grain de papier subtile est appliquée comme superposition fixe en plein écran. Elle se trouve à z-index: 9999 — au-dessus de tout — mais pointer-events: none assure qu'elle n'intercepte jamais les interactions.
.grain-overlay {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 9999;
opacity: var(--grain-opacity, 0.035);
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
background-repeat: repeat;
background-size: 200px 200px;
transform: translateZ(0);
will-change: transform;
transition: opacity 0.35s var(--ease-out);
}
/* En mode sombre, le mélange d'écran révèle le grain plus naturellement */
:root[data-theme="dark"] .grain-overlay {
mix-blend-mode: screen;
}
Dans Flutter : Reproduisez ceci en utilisant un widget CustomPaint en haut de l'arbre de widgets avec un motif de bruit basé sur un shader, ou cuisez le grain en tant qu'actif PNG avec une opacité d'environ 3 % et utilisez BlendMode.screen en mode sombre.
Section 5 — Bascule de Thème (Commuteur Céleste)
Le bouton de bascule de thème est un petit bouton en forme de pilule positionné en haut à droite. Il
…
[tronqué pour la traduction]