init docs #192

Merged
Nora merged 9 commits from feature/motion-kaleido-fold into develop 2026-09-13 19:36:38 +00:00
Owner
No description provided.
init docs
All checks were successful
CI / Renderer - couverture JS (pull_request) Has been skipped
CI / Renderer - audit des dépendances JS (pull_request) Successful in 39s
CI / PHP - tests + static + lint (pull_request) Successful in 7m15s
CI / Renderer - tests + lint JS (pull_request) Successful in 6m57s
2b34ac7c35
`foldPolar` et `sampleFieldTable` sont inlinés dans la boucle pixel, les bornes
de table hissées hors de la boucle, et la géométrie (`hypot`/`atan2`) remplie par
rangée dans deux `Float64Array(width)` réutilisés. Les libs ne bougent pas : cinq
algos les partagent, l'optimisation reste dans `kaleido-fold.js`.

À l'octet près. L'arithmétique est recopiée opération par opération, dans le même
ordre — le repli travaille sur le secteur entier (pas le domaine fondamental), le
tour flottant `(a + rotation) - rotation` est conservé tel quel, et `fu`/`fv` ne
sont pas factorisés. Un en-tête nomme les trois pièges ; le prochain passage qui
« simplifie » saura pourquoi il casse le golden.

Un second golden, NON CARRÉ (96 × 64), rejoint le filet : sur un carré, une
inversion width/height dans un tampon de rangée est invisible. C'est précisément
la classe de bug que cette tranche introduit.

Banc estampe, 1557 × 1920, n=25, médiane : 353,7 → 300,4 ms/frame. Le golden
64 × 64 est inchangé, `ENGINE_VERSION` ne bouge pas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYuzMrWTmyMxYSc4hwbK1K
La table de champ (`polarTableSize` + `fieldColor`) ne dépend que du
contenu fréquentiel, de la palette, `half` et `wedge` — jamais de la
rotation. `phase` ne touchant qu'à `rotation`, un clip vidéo de 450
frames reconstruisait 450 fois la même table pour rien (33,7 ms
pièce).

`tableOf(clip, rng)` extrait le calcul tel quel ; `slateOf(cache,
clip, rng)` le mémoïse sur `config.videoCache` (posée par
video/source.js), avec une clé qui porte tout ce dont la table
dépend et rien d'autre (pas rotationDeg/phaseShift/spacing). Le
chemin estampe n'a pas d'ardoise et recalcule toujours tout, pour les
mêmes octets. `createNoise2D` reste DANS `tableOf` : c'est le dernier
consommateur de rng du module, le sortir ferait payer les 255 tirages
à chaque frame chaude pour rien.

Trois tests posés en RED puis GREEN : parité exacte film/print, même
octets ardoise froide ou chaude (une seule ardoise par clip), et
non-réutilisation d'une ardoise entre deux jeux de params de champ
(le bug à un coup si une clé oublie un param). Aucun `rng()` ajouté
ni déplacé, `ENGINE_VERSION` et les deux goldens inchangés.

npm test -- generative/algorithms/kaleido-fold.test.js : 31/31 verts.
npm run lint : 0 erreur (108 warnings no-console préexistants).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYuzMrWTmyMxYSc4hwbK1K
`Math.hypot`/`Math.atan2` ne dépendent que du pixel, jamais de la
rotation : un clip vidéo de 450 frames refaisait donc 1,35 milliard
d'appels transcendants pour retrouver les mêmes 3 millions de
valeurs. `polarSlate(cache, dims)` les mémoïse pleine image
(2 × Float64Array, 48 Mo à 1557×1920) sur `config.videoCache`, avec
une clé qui porte width/height/cx/cy/half. Le chemin estampe (3543 ×
4370 → 248 Mo) n'alloue JAMAIS cette ardoise : les tampons de rangée
de T01 restent son seul chemin. Le branchement tableau/offset se
fait une fois par rangée, jamais par un ternaire par pixel — le
corps de la boucle ne change pas.

Les deux filets de T02 sont étendus à un second couple de tailles
non carré (96×64), pour la même raison qu'au T01 : une inversion
width/height est invisible sur un carré. Le test à dents de cette
tranche (« does not reuse a polar slate across frame sizes ») garde
le bug à un coup : une ardoise de 64×64 relue dans une boucle de
96×64 ne lève rien, elle rend n'importe quoi. Deux ardoises
partagent maintenant la même Map (table de champ + géométrie) : les
assertions de taille de cache de T02 sont ajustées en conséquence
(1→2, 2→3).

Gain mesuré au chemin de prod exact (recomputeFrameFor + phasePath,
1557×1920, 450 frames, un process, machine de dev 12 cœurs) :
moy 182,1 ms/frame (med 178,3), contre 351,3 ms avant T01-T03 —
56 % du budget de 315 ms. Piège de mémoire consigné dans le fichier
de tâche : kaleido-fold retient ~24,5 Mo/frame (vs ~14,4 pour
`pour`), un clip complet culmine à ~11,3 Go — MemoryMax=10G (la
valeur d'exemple du dossier) ne suffit pas, 20G est nécessaire.

Aucun rng() ajouté ni déplacé. ENGINE_VERSION et les deux goldens
inchangés.

npm test -- generative/algorithms/kaleido-fold.test.js : 32/32 verts.
npm test (suite complète) : 2960 tests, 2958 pass, 2 fail — les deux
dérives SIMD pipeline-slide préexistantes, sans rapport.
npm run lint : 0 erreur (108 warnings no-console préexistants).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYuzMrWTmyMxYSc4hwbK1K
24 clips complets (450 frames, un process chacun, MemoryMax=20G) au
chemin de prod exact (recomputeFrameFor + phasePath, 1557×1920,
SAMPLE_PALETTE, hash a1b2c3d4…) : défauts, 20 tirages uniformes du
paramSpec (loi exacte de StandardArtworkDraftFactory::drawValue()),
et trois coins (tous maxima ; maxima + sectors:6 ; + mirror:off, sur
la mise en garde « le coin n'est pas la conjonction des maxima »).

Résultat : 0/20 tirages au-dessus de 315 ms, pire moyenne de clip
182,9 ms (défauts, 41,9 % de marge), pire médiane 179,7 ms
(tirage-2, 43,0 % de marge). Le coin, redouté cher, ne l'est plus en
régime permanent (173,5-176,1 ms de médiane, sous les défauts) : sa
construction de table est passée à l'ardoise (T02) et s'est
entièrement déplacée sur la PREMIÈRE frame du clip (324 à 713 ms
selon les params, contre 324-179 ms en régime permanent) — la
réserve §7 du plan change de cible sans devenir fausse.

Confirme sur 24 clips le piège de mémoire trouvé en T03 :
~24,5 Mo/frame de RSS côté Rust, ~11,3 Go/clip, MemoryMax=10G (la
valeur d'exemple du dossier, calibrée sur pour/low-mist) insuffisant
ici — 20G nécessaire. À reporter dans 00-index.md en T08.

Corrige au passage une inexactitude de doc sans effet sur le code :
le @returns de tableOf/slateOf (T02) annonçait Float64Array pour la
table, alors que buildFieldTable rend un Uint8ClampedArray.

Issue retenue : (1) sous le budget → T05 pose meta.motion = 'phase'.

Banc jetable hors dépôt (scratchpad), aucun code applicatif modifié
par la mesure elle-même.

npm test -- generative/algorithms/kaleido-fold.test.js : 32/32 verts.
npm run lint : 0 erreur.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYuzMrWTmyMxYSc4hwbK1K
Le banc de T04 tient le budget (182,9 ms/frame au pire cas, 41,9 %
de marge sous 315 ms) : kaleido-fold n'a plus de raison de rester en
repli ken-burns. `motion: undefined` retiré de l'appel kaleidoSuite
(test rouge constaté d'abord : `declares its phase loop` attendait
`'phase'`, obtenait `undefined`) puis `meta.motion = 'phase'` posé —
le module rejoint les quatre autres kaléidoscopes.

En-tête de motion du module réécrit dans l'ordre demandé : (1) phase
est une rotation rigide exacte, (2) la boucle est sans couture par
invariance D_n (0 octet différent sur 11 957 760, vérifié), (3) le
refus du 2026-08-29 condamnait un chemin, pas la motion — les deux
mesures (330 ms puis 351,3 ms avant T01-T03, 182,9 ms après) côte à
côte, (4) ce que l'ardoise de clip garde et pourquoi l'estampe ne
l'a pas.

Présentation pure : rien de tout ceci n'entre dans canonical_hash,
la signature ou le body renderer. ENGINE_VERSION et les deux
goldens inchangés.

npm test -- generative/algorithms/kaleido-fold.test.js : 32/32 verts.
npm test (suite complète) : 2960 tests, 2958 pass, 2 fail — les deux
dérives SIMD pipeline-slide préexistantes, sans rapport.
npm run lint : 0 erreur.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYuzMrWTmyMxYSc4hwbK1K
Les trois emplacements en lockstep : renderer/generative/video/
version.js, VideoFormatCatalog.php, VideoFormatCatalogTest.php.
PHPUnit d'abord (RED : assertSame('1.26.0', ...) contre la constante
encore à '1.25.0'), puis les trois valeurs.

Entrée de journal dans version.js, dans le style des précédentes :
kaleido-fold quitte le repli ken-burns générique porté depuis le
2026-08-29 (T36) pour 'phase', une rotation rigide exacte (boucle
sans couture par invariance D_n, 0 octet différent sur 11 957 760
vérifié). Le refus de T36 condamnait un chemin, pas la motion —
troisième fois de suite après oil-sheen (1.24.0) et rain-glass
(1.25.0) — et le banc T04 le confirme : 182,9 ms/frame au pire cas
contre 351,3 ms avant, 41,9 % de marge sous les 315 ms de budget.

ENGINE_VERSION (moteur d'image) ne bouge pas : c'est une version
distincte, et l'estampe est inchangée à l'octet. Aucune migration,
aucun app:catalog:sync, aucun certificat à refaire — kaleido-fold
est `active: false`, le bump est gratuit.

docker compose exec app vendor/bin/phpunit --filter
VideoFormatCatalogTest : OK (2 tests, 3 assertions).
mago lint + phpstan analyse sur les fichiers PHP touchés : verts.
npm test (renderer) : 2960 tests, 2958 pass, 2 fail — les deux
dérives SIMD pipeline-slide préexistantes, sans rapport.
npm run lint : 0 erreur.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYuzMrWTmyMxYSc4hwbK1K
node gen-video-local.mjs kaleido-fold, LOCAL_SCALE = 1 (résolution de
prod), un process sous systemd-run (MemoryMax=24G, cgroup), défauts.

450 frames en 1m49,800s de mur (~244 ms/frame de bout en bout,
encodage ffmpeg + bandes + mux compris, contre 182,9 ms de compute
seul au pire cas T04 — l'écart est l'encodage, pas une régression).
MP4 : 6 988 471 octets (6,99 Mo), ffprobe confirme 450 frames à
30 fps, 15,000 s exactement.

La couture est vérifiée à l'OCTET, pas à l'œil : écart moyen par
canal RGB entre f449→f0 (couture) et f0→f1 (pas ordinaire) sont
NUMÉRIQUEMENT IDENTIQUES (3,85356 dans les deux cas, max 28/255) —
re-dérivé indépendamment (script verify-seam.mjs, chemin de prod
exact recomputeFrameFor + phasePath). L'écart à demi-période
(55,90863, ~14,5×) confirme que le mouvement se lit vraiment : la
boucle n'est pas silencieuse par accident, c'est l'invariance D_n
(T01) qui la rend exacte.

Les cinq points de contrôle verdictés : boucle sans saut, coins
calculés (aucun aplat de fond), vitesse de rotation lisible (36° aux
défauts), pas de scintillement de grain perceptible, centre tenu —
l'argument de départ contre ken-burns est confirmé. Noté sans en
faire une réserve : la bande CTA alterne son texte au bouclage,
comportement générique des overlays commun à tous les reels, pas
une régression kaleido-fold.

LOCAL_SCALE remis à 4 dans le dépôt (git status confirmé propre sur
gen-video-local.mjs) — aucun code applicatif modifié par cette
tâche de vérification.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYuzMrWTmyMxYSc4hwbK1K
end
All checks were successful
CI / Renderer - couverture JS (pull_request) Has been skipped
CI / Renderer - audit des dépendances JS (pull_request) Successful in 1m12s
CI / PHP - tests + static + lint (pull_request) Successful in 5m36s
CI / Renderer - tests + lint JS (pull_request) Successful in 6m15s
f969a43129
Nora merged commit 2193bd20f4 into develop 2026-09-13 19:36:38 +00:00
Nora deleted branch feature/motion-kaleido-fold 2026-09-13 19:36:38 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Nora/ArtAutomatic!192
No description provided.