Que fait teardown ?
Une machine, une page. Le visiteur voit le mécanisme fonctionner, appuie sur un bouton, et la pièce en action s'ouvre tandis que les jauges autour affichent les vraies valeurs. Sans intervention, la page se visite toute seule avec un curseur. Le même code enregistre un film de la visite, image par image, avec une musique construite sur la même chronologie.
SKILL_DIR ci-dessous est le dossier où se trouve ce fichier (pour une installation Cursor, généralement ~/.cursor/skills/teardown, ~/.agents/skills/teardown, ou .cursor/skills/teardown dans un projet). Les builds et rendus vont dans ./teardown-out du dossier depuis lequel vous exécutez les commandes.
Première exécution
cd "$SKILL_DIR" && npm install && npx playwright install chromium
Les pages n'ont besoin de rien d'autre. La vidéo nécessite ffmpeg dans le PATH et la musique nécessite Python 3 (bibliothèque standard uniquement). Définissez FFMPEG, PYTHON ou CHROMIUM pour pointer vers d'autres binaires.
Les 3 exemples
Construisez-en un, ouvrez le HTML, appuyez sur les boutons. Copiez le plus proche lorsque vous commencez une nouvelle machine.
| La machine | Ce qui l'anime | Ce qu'il faut garder | |
|---|---|---|---|
v8-* | Un V8 à plan de croisement avec chemises en verre : la charge brûle à l'intérieur du cylindre que vous suivez, les soupapes se lèvent sur leurs cames, 8 pistons bougent à partir du système bielle-manivelle exact. | Angle de vilebrequin. Ordre d'allumage 1-8-4-3-6-5-7-2, un modèle de pression de chambre pour le diagramme indicateur. | Modes de coupe (verre, section, solide), l'ordre d'allumage comme sélecteur de cylindre, des graphiques en direct synchronisés avec le vilebrequin. |
cessna-* | Le train d'atterrissage principal du Cessna 337 se repliant dans la cellule au décollage et se déployant à l'atterrissage. | Course 0..1 : une crémaillère de 201 mm entraîne un pignon de 32 dents (module 4 mm) sur exactement 180°. | Un seul degré de liberté animant tout un mécanisme, les phases de vol en fonction du temps, une piste qui défile sous le modèle. |
strandbeest-* | Le Strandbeest de Theo Jansen, 20 pattes sur un seul vilebrequin, marchant de côté sur le sable. | Vent. La vitesse du vilebrequin en est déduite ; chaque articulation suit par intersection de cercles à partir des 11 longueurs de liaison de Jansen. | Un solveur de liaison exact en 67 lignes, des tubes instanciés, des traces de pieds, un graphique de contact des 20 pieds. |
Chacun se compose de 3 dossiers : <nom>-shared/ contient la machine, <nom>-film/ la visite enregistrée, <nom>-live/ la page que vous pilotez.
node "$SKILL_DIR/sims/build.mjs" v8-live # → teardown-out/dist/v8-live.html, hors ligne, ~800 Ko
node "$SKILL_DIR/sims/build.mjs" # tous les 6
Comment une machine est construite
Un dossier par machine, divisé par tâche. Les exemples suivent ceci exactement :
| Fichier | Tâche |
|---|---|
kin.js / gear.js / jansen.js | Les maths. Dimensions réelles en unités réelles, une entrée (angle vilebrequin, course, vent) et chaque pose et valeur en fonction de celle-ci. Pas de three.js ici. |
engine.js / gear.js / beast.js | La géométrie, construite en code : pièces tournées, tubes, liaisons instanciées. update(input) la pose. |
stage.js | Studio, lumières, ombres, post-traitement (GTAO, bloom). frame(state, cam) dessine une image. |
console.js | La superposition : mise en page CSS fixe 1600 x 900 de panneaux, graphiques, interrupteurs, légendes avec lignes de repère. update(state) la redessine à partir de l'état de l'image. |
film.js | Un SCRIPT de mouvements de l'opérateur (vues, isolement, coupe, accélérateur) et render(t) comme fonction pure du temps. |
live.js | La même machine en temps réel : boutons, curseurs, orbite, zoom, touches. Sans entrée, il joue le script de film.js comme une visite automatique avec un curseur ; tout clic, glisser, molette ou touche rend le contrôle, 25 s de silence le rend. |
score.py | Le son sur la chronologie du film. |
Pour une machine en dehors de SKILL_DIR, créez un dossier avec un main.js et importez le kit par son nom : import {runSim} from 'teardown-kit/runtime.js'. Construisez-la avec node "$SKILL_DIR/sims/build.mjs" ./my-machine.
Règles qui décident si cela fonctionne
- Partez d'une référence, jamais de l'imagination. Une photo, un dessin en coupe d'un manuel, un clip de la vraie chose. Construisez par rapport à elle et comparez image par image. Les machines inventées à partir d'une phrase deviennent génériques à chaque fois ; le même modèle reconstruit une machine réelle de près quand il a quelque chose à égaler.
- Des chiffres réels, une seule source. Obtenez d'abord les vraies dimensions (alésage, course, nombre de dents, longueurs de liaison). Chaque jauge, graphique et étiquette lit la même fonction qui pose les pièces, donc rien à l'écran ne peut contredire le mouvement. Vérifiez-en un à la main : dans le Cessna, 32 dents × module 4 mm donne un diamètre primitif de 128 mm, et la moitié de sa circonférence correspond à la course de 201 mm.
- Une seule entrée pilote tout. Posez à partir de l'angle de vilebrequin, de la course ou du vent. Rien n'est keyframe manuellement, donc le film, la page en direct et la musique ne dérivent jamais.
- La pièce qui travaille s'ouvre. Isolez-la, coupez-la, radiographiez-la. Une caméra qui va à l'intérieur vaut plus que dix orbites.
- Studio lumineux, une seule accentuation. Les fonds pâles se lisent dans un flux ; les fonds sombres perdent la première seconde. L'accentuation marque ce qui change. Surveillez les pièces presque blanches sur un fond pâle : donnez-leur un contour ou un sol plus foncé.
- Choisissez la caméra pour le mécanisme. Une liaison plane vue de face se réduit à un treillis ; une vue 3/4 le long de la colonne vertébrale garde chaque jambe lisible.
- Corrigez les collisions avec un nombre. Quand une pièce en traverse une autre, redimensionnez-la ou déplacez-la dans le bloc de paramètres. Ne la cachez jamais avec la caméra.
Règles de la page en direct
- Testez sur un GPU intégré. Une page qui tourne à 60 ips sur une carte de bureau peut tomber à 15 ips sur le GPU intégré d'un portable. Les exemples ont des niveaux de qualité (
TIERSdanslive.js) : pas d'AO, rapport de pixels plus faible, cartes d'ombres plus petites, panneaux redessinés une image sur deux. Trouvez d'abord le shader coûteux : un déplacement calculé 5 fois par sommet coûte plus que tous les niveaux ensemble. - Préchauffez les shaders.
kit/warm.jscompile chaque programme en parallèle avant la première image, donc la page ne gèle jamais au premier dessin. - Gardez la page sous 1 Mo. Les robots d'exploration de liens (X, Slack) lisent la carte de partage depuis le HTML et abandonnent sur une page de 15 Mo. Les grands modèles sortent sous forme de fichiers à côté de la page :
build.json→{"external": {"heavy.glb": "light.glb"}}.
Contrat render(t)
import {runSim} from '../kit/runtime.js';
const DEFAULTS = {duration: 20, fps: 60, hud: {enabled: false}, director: {enabled: false}};
runSim(DEFAULTS, async ({cfg, canvas, capture}) => {
// construire la scène, précalculer tout ce qui est avec état
return {render(t) { /* dessiner l'image t à partir de zéro */ return {}; }, resize() {}};
});
render(t)est pure : pas deMath.random(utilisezrng(seed)depuiskit/util.jslors de la configuration), pas deDate, pas d'état transporté entre les images. La capture l'appelle à des moments arbitraires.- Tout ce qui bouge selon ses propres règles (agents, particules) est simulé une fois au chargement dans des tableaux typés ;
renderne fait que les lire. Une quantité intégrée dans le temps (le vilebrequin du Strandbeest sous un vent changeant) est intégrée sous forme fermée ou tabulée au chargement. - Chaque temps fort va dans
<nom>-film/timeline.jsonen secondes. La musique lit le même fichier. - L'image 0 est la vignette. Elle doit déjà montrer la machine.
Commandes
node "$SKILL_DIR/sims/build.mjs" v8-film
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --stills beats --cols 4 --out teardown-out/v8-beats.png
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --still 12.5 --out teardown-out/v8-12.5.png
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --out teardown-out/v8-silent.mp4
python "$SKILL_DIR/run_sfx.py" "$SKILL_DIR/sims/v8-shared/score.py"
ffmpeg -y -i teardown-out/v8-silent.mp4 -i teardown-out/v8-score.wav -map 0:v -map 1:a -c:v copy -c:a aac -b:a 256k -shortest -movflags +faststart teardown-out/v8.mp4
node "$SKILL_DIR/wave.mjs" teardown-out/v8.mp4 --timeline "$SKILL_DIR/sims/v8-film/timeline.json"
--size est la mise en page CSS et --dpr la multiplie : 1600 x 900 à 1.2 donne 1920 x 1080. La capture affiche le GPU obtenu ; un rendu logiciel signifie que les flags GPU dans paths.mjs n'ont pas pris effet.
Boucle de relecture
Vous ne pouvez pas regarder la vidéo ; vous pouvez regarder les images. Ne signalez jamais une machine comme terminée sans lire des planches du rendu actuel.
--stills beats: une vignette par temps fort de la chronologie, 0.3 s après, chacune étiquetéet=.- Lisez chaque vignette par rapport à la liste de contrôle ci-dessous.
- Zoomez :
--stills every:0.2 --from A --to Bpour une transition,--still Tpour une image complète. - Corrigez, reconstruisez, retournez à 1. Arrêtez-vous quand un passage complet ne trouve rien.
- Final :
node "$SKILL_DIR/sheet.mjs" --video <final.mp4> --timeline <timeline.json>et lisez-le aussi : il montre ce que l'encodeur a écrit.
Liste de contrôle :
- Le mécanisme. Chaque pièce qui doit toucher touche ; rien ne traverse quoi que ce soit ; les chiffres sur les panneaux correspondent à la pose.
- Composition. Un point focal par image. Rien d'important à moins de 60 px d'un bord. Les étiquettes ne couvrent jamais la pièce qu'elles nomment.
- Typographie. Rien de rogné. La valeur clé se lit à la largeur d'un téléphone.
- 3D. Le bloom mange les détails : gardez les calques émissifs sous 1.0. Les surfaces presque blanches explosent. Le métal brillant sous une faible lumière fait des stries : rugosité ≥ 0.45 et envMapIntensity ≈ 0.5 sur les grandes surfaces.
- Temporisation. Chaque état dure assez longtemps pour être lu : 1 s pour une phrase courte plus 0.25 s par mot au-delà de trois.
Pièges three.js déjà rencontrés dans les exemples
smoothstep(a, b, x)aveca > bretourne 0 sur Windows (ANGLE/D3D). Écrivez1.0 - smoothstep(b, a, x).- Un
ShadowMaterialou un décalque à une fraction de millimètre au-dessus du sol perd le test de profondeur dans une cible de rendu de post-traitement. Donnez-luipolygonOffset. - Un quad posé au sol avec un mapping miroir est éliminé comme une face arrière. Utilisez
DoubleSide. - Un pixel NaN noircit toute l'image à travers le bloom. Clampez chaque base de
pow()dans un shader. - Le GTAO sur un modèle coupé (sectionné) a besoin des mêmes plans de coupe sur
gtao.normalMaterial, sinon la moitié coupée revient comme un fantôme pâle.
Son
sfx/ synthétise chaque son en Python pur (48 kHz, reproductible) et lit la chronologie du film, donc le son ne peut pas dériver hors synchro. python "$SKILL_DIR/run_sfx.py" --list montre les générateurs. sample() ajoute les sons CC0 enregistrés dans sfx/samples/. sfx/score_kit.py a les nappes et les accents que les 3 partitions utilisent : une nappe d'accords, un bruit sourd par temps de puissance, un moteur, de l'air sous une traînée.
- Chaque instant vient de la chronologie, jamais d'un nombre tapé.
- Le mastering est automatique : −14 LUFS, pic vrai ≤ −2 dBFS.
- Accent, jamais narration : un mouvement continu reste silencieux. Une touche pour chaque son tonal.
Goût, avec des chiffres
- Easing : entrées
cubic-bezier(0.16, 1, 0.3, 1), sortiescubic-bezier(0.6, 0, 0.9, 0.35)à la moitié de la durée d'entrée, état à étatcubic-bezier(0.65, 0, 0.35, 1). Linéaire uniquement pour le mouvement continu. - La machine remplit 60 à 70 % de son viewport. Les étiquettes jamais en dessous de 34 px sur un canevas 1080.
- Une seule accentuation, et elle signifie quelque chose : la pièce qui travaille en ce moment.
- Rien de complètement immobile : un élément toujours vivant.
Crédits
Portage Cursor par bugeng777/teardown-cursor de elvarofficial/teardown (MIT). Le kit, la capture d'images, le moteur SFX et les règles de relecture viennent de whaleyxbt/claude-motion (MIT). Les échantillons enregistrés sont CC0 de Freesound, réduits par Barty-Bart/motion-graphics (MIT) ; sources dans sfx/samples/SOURCES.md.