Que fait handdrawn-3d ?
Vous modélisez le sujet en 3D avec quelques solides simples, et le kit le dessine à la main. Les faces reçoivent trois tons plats de marqueur provenant d'une lumière située en haut à gauche. Les faces voisines de même ton se fondent en une seule zone. Le contour est encré épais et les plis plus fins, avec des lignes tremblantes qui s'effilent, sur du papier crème. La scène est dessinée une fois par image avec t parcourant une boucle. Le résultat est un SVG animé en boucle : les images sont commutées par CSS, sans script, donc il fonctionne dans les navigateurs et les balises <img>. Le texte utilise une police manuscrite intégrée avec prise en charge complète du vietnamien.
Kit : assets/kit.js · moteur de rendu : assets/render.mjs · chaque fonction et option : references/kit.md (lisez-le avant d'écrire une scène) · exemples commentés : examples/ (tasse, théière, grille-pain, moulin à vent : lisez le plus proche).
Configuration (une fois)
L'export PNG/GIF nécessite @resvg/resvg-js. Si render.mjs indique qu'il est manquant, exécutez npm install dans le dossier de cette compétence. Le SVG lui-même ne nécessite rien.
Avant de dessiner
- Est-ce dessinable ? Si le sujet est abstrait (« espoir », « productivité »), ne dessinez pas quelque chose de vague. Suggérez une ou deux scènes concrètes qui le représentent, puis dessinez celle que l'utilisateur choisit.
- Diagrammes, schémas, UI, boutons, choses interactives : pas cette compétence.
- Qu'est-ce qui bouge ? Chaque image anime l'objet lui-même : la caméra ne bouge jamais. Choisissez un ou deux mouvements qui appartiennent au sujet. Le couvercle d'une bouilloire tremble et émet de la vapeur. Le pain saute. Les ailes d'un moulin à vent tournent. Un ventilateur tourne. La queue d'un chat balaye. Une lampe hoche la tête. Une plante se balance. Si l'utilisateur nomme un mouvement, utilisez celui-ci. Si rien ne peut plausiblement bouger, utilisez de la vapeur, un léger hochement ou un balancement, et l'agitation naturelle des lignes.
Flux de travail
- Pièces. Listez les vraies pièces du sujet et comment chacune est construite à partir de solides. Écrivez-le sous forme de tableau en commentaire en haut de la scène : pièce · appel · taille/position · couleur. Modélisez à partir des vraies pièces (rebords, couvercles, boutons, poignées, pieds, fentes, charnières), pas un bloc avec un nom dessus. Vérifiez les proportions si vous n'êtes pas sûr.
- Modélisez dans
scene.js(monde : x à droite, y vers l'arrière, z vers le haut, sol z = 0 ; unités en mm approximativement ; cadrage automatique) :- les objets ronds que l'on pourrait tourner sur un tour →
k.lathe(les contenants utilisentwall:) ,k.cylinder,k.sphere - les objets parallélépipédiques →
k.box(round:pour les coins arrondis d'appareils), les contours irréguliers →k.extrude - poignées, becs, tuyaux, pieds, câbles, tiges →
k.tube, en commençant à l'intérieur du corps (il est coupé à la surface) - le contenu d'un contenant →
{ in: container }; marques plates sur une face →k.panel/k.lineavec{ on: solid } - tournez tout le sujet avec
k.group({ rotate: { z: 45 } }, …)quand sa « vue de côté » doit faire face au spectateur (un bec de théière à gauche et l'anse à droite)
- les objets ronds que l'on pourrait tourner sur un tour →
- Animez avec
t∈ [0, 1) : les pièces mobiles vont dans unk.group({ about, rotate, at }, …)piloté park.wave(),k.pulse()ou360 * t. Chaque mouvement doit revenir à son point de départ àt = 1. - Rendez et vérifiez :
Ouvreznode <skill>/assets/render.mjs scene.js -o out/scene.svg --png out/scene.png --strip --thumbout/scene.png(une image fixe) etout/scene-frames.png(6 images sur la boucle) avec l'outil de lecture et regardez-les. Ajoutez--gridpour lire les coordonnées de la feuille. Vérifiezout/scene-128.png: il doit encore être reconnaissable comme le sujet à 128 px. - Corrigez et rendez à nouveau. Vérifiez :
- Est-ce que ça se reconnaît comme le sujet au premier coup d'œil ? La silhouette d'abord.
- Rien dessiné dans le mauvais ordre : une pièce qui apparaît à travers un corps, une pièce lointaine par-dessus une proche, un contenu caché ou qui dépasse. Corrigez avec les règles sous Comment les solides sont ordonnés dans
references/kit.md: solides séparés,in:,on:, modélisez seulement ce qui dépasse d'une ouverture, etlayeren dernier recours. - Les pièces touchent ce qui les maintient. Rien ne flotte sauf si nécessaire (un couvercle qui saute).
- Le mouvement se lit dans la bande d'images et boucle sans saut.
- Les étiquettes se trouvent dans les marges et ne traversent pas le dessin plus que nécessaire.
Répétez 4–5 jusqu'à ce que ce soit correct (généralement 2–4 essais). Rendez la version finale sans
--grid.
Ne livrez jamais sans avoir regardé l'image fixe et la bande d'images. Livrez le chemin du SVG (l'image animée), plus le PNG, et montrez le PNG. Ajoutez --gif out/scene.gif quand l'utilisateur veut un GIF ou quand le SVG doit être placé dans un endroit qui ne lit pas l'animation SVG (applications de chat, certains clients email).
Règles de style
- Un seul aspect : encre + tons plats de marqueur sur papier. Pas de dégradés, lueurs, flous, astuces d'opacité,
<text>SVG ou SVG brut. Utilisez uniquement le kit. - Couleur : noms de palette (voir
references/kit.md), 3–5 par image plus l'encre. Les noms de palette rendent le mieux ; tout hexadécimal est adouci. Les tons clair, moyen et foncé proviennent automatiquement de chaque remplissage. Ne simulez pas l'ombrage avec des solides supplémentaires. - Caméra : isométrique par défaut. Modifiez
sheet.cameraseulement pour une raison. Une inclinaison plus faible (20–25) et un lacet de 25–35 donnent une « vue produit » plus conviviale pour les objets hauts (tours, bouteilles, lampes, personnes). - Simple et massif : quelques solides propres se lisent mieux que beaucoup de petits détails. Les petites pièces (boutons, pieds, poignées) sont ce qui rend le dessin réaliste : ajoutez-les.
- Ancrez-le : les ombres sont automatiques. Quelque chose posé sur une planche, une table ou une soucoupe projette son ombre dessus. Une planche, un plateau, une motte ou une table sous un petit objet l'aide à se situer dans l'espace.
- Texte :
k.title(...)facultatif en haut à gauche, plus de courtes notes de marge en minuscules (k.label) pointant vers des points 3D. Écrivez-les dans la langue de l'utilisateur. Pas de boîtes ni de bulles par-dessus le dessin. - Feuille : 1000×1000 par défaut. Pour les scènes larges, utilisez
export const sheet = { width: 1200, height: 900 }.--transparentsupprime le papier. - Taille de l'animation : 16 images à 12 ips (une boucle de 1,3 s) par défaut ; un SVG typique fait 0,5–1 Mo. Pour un mouvement lent, utilisez
sheet.fps = 8. Gardezframes≤ 24.
Modèle de scène
// Une théière sur un trépied ; le couvercle tremble.
// pièce appel taille / emplacement couleur
// trépied cylinder r 120, h 10 bois
// corps lathe { smooth } r 55→94→50, h 118, sur le trépied canard
// bec tube [14, 7] de l'intérieur du corps, vers la gauche canard
// anse tube 8 les deux extrémités à l'intérieur du corps, côté droit canard
// couvercle+ lathe + sphere dans un groupe articulé sur son bord arrière canard, ocre
// bouton
export const sheet = { seed: 3 };
export function draw(k, t = 0) {
k.cylinder([0, 0, 0], 120, 10, { fill: 'wood' });
k.group({ rotate: { z: 45 } }, () => { // bec à gauche de l'écran, anse à droite
k.lathe([0, 0, 10], [[55, 0], [78, 10], [94, 45], [90, 85], [68, 112], [50, 118]], { fill: 'teal', smooth: true });
k.tube([[-78, 0, 50], [-112, 0, 66], [-128, 0, 100], [-146, 0, 118]], [14, 7], { fill: 'teal' });
k.tube([[70, 0, 112], [112, 0, 108], [122, 0, 72], [84, 0, 40]], 8, { fill: 'teal' });
const hop = Math.max(0, k.wave(0, 2 * t)); // 0..1, deux sauts par boucle
k.group({ about: [44, 0, 128], rotate: { y: -18 * hop }, at: [0, 0, 16 * hop] }, () => {
k.lathe([0, 0, 127], [[52, 0], [50, 5], [30, 13], [8, 18], [0, 19]], { fill: 'teal', smooth: true });
k.sphere([0, 0, 152], 10, { fill: 'ochre' });
});
k.steam([-150, 0, 125], { h: 90, n: 2, spread: 18 });
});
k.label('couvercle qui tremble', { to: [0, 0, 140], side: 'right' });
}