@autoaiai/aicut 0.1.7 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/MANUAL.md +94 -84
  2. package/package.json +1 -1
  3. package/product.json +2 -1
  4. package/skills/aicut/SKILL.md +4 -4
  5. package/skills/aicut/references/commands.md +15 -15
  6. package/skills/aicut/references/film-format.md +1 -1
  7. package/skills/aicut/references/recipes.md +4 -4
  8. package/skills/aicut/references/troubleshooting.md +2 -2
  9. package/skills/aicut-motion/SKILL.md +75 -9
  10. package/skills/aicut-motion/THIRD_PARTY_NOTICES.md +14 -0
  11. package/skills/aicut-motion/assets/atlas/lib/harness.js +116 -0
  12. package/skills/aicut-motion/assets/atlas/lib/sound.js +274 -0
  13. package/skills/aicut-motion/assets/atlas/styles/001-flat-vector-science/code.js +937 -0
  14. package/skills/aicut-motion/assets/atlas/styles/001-flat-vector-science/poster.jpg +0 -0
  15. package/skills/aicut-motion/assets/atlas/styles/001-flat-vector-science/style.json +13 -0
  16. package/skills/aicut-motion/assets/atlas/styles/002-watercolor-wash/code.js +909 -0
  17. package/skills/aicut-motion/assets/atlas/styles/002-watercolor-wash/poster.jpg +0 -0
  18. package/skills/aicut-motion/assets/atlas/styles/002-watercolor-wash/style.json +13 -0
  19. package/skills/aicut-motion/assets/atlas/styles/003-shadow-puppet-theatre/code.js +881 -0
  20. package/skills/aicut-motion/assets/atlas/styles/003-shadow-puppet-theatre/poster.jpg +0 -0
  21. package/skills/aicut-motion/assets/atlas/styles/003-shadow-puppet-theatre/style.json +13 -0
  22. package/skills/aicut-motion/assets/atlas/styles/004-whiteboard-explainer/code.js +897 -0
  23. package/skills/aicut-motion/assets/atlas/styles/004-whiteboard-explainer/poster.jpg +0 -0
  24. package/skills/aicut-motion/assets/atlas/styles/004-whiteboard-explainer/style.json +13 -0
  25. package/skills/aicut-motion/assets/atlas/styles/005-psychedelic-poster/code.js +814 -0
  26. package/skills/aicut-motion/assets/atlas/styles/005-psychedelic-poster/poster.jpg +0 -0
  27. package/skills/aicut-motion/assets/atlas/styles/005-psychedelic-poster/style.json +13 -0
  28. package/skills/aicut-motion/assets/atlas/styles/006-tech-glow-explainer/code.js +990 -0
  29. package/skills/aicut-motion/assets/atlas/styles/006-tech-glow-explainer/poster.jpg +0 -0
  30. package/skills/aicut-motion/assets/atlas/styles/006-tech-glow-explainer/style.json +13 -0
  31. package/skills/aicut-motion/assets/atlas/styles/007-papercraft-models/code.js +994 -0
  32. package/skills/aicut-motion/assets/atlas/styles/007-papercraft-models/poster.jpg +0 -0
  33. package/skills/aicut-motion/assets/atlas/styles/007-papercraft-models/style.json +13 -0
  34. package/skills/aicut-motion/assets/atlas/styles/008-1940s-film-noir/code.js +792 -0
  35. package/skills/aicut-motion/assets/atlas/styles/008-1940s-film-noir/poster.jpg +0 -0
  36. package/skills/aicut-motion/assets/atlas/styles/008-1940s-film-noir/style.json +13 -0
  37. package/skills/aicut-motion/assets/atlas/styles/009-manim-style-math/code.js +840 -0
  38. package/skills/aicut-motion/assets/atlas/styles/009-manim-style-math/poster.jpg +0 -0
  39. package/skills/aicut-motion/assets/atlas/styles/009-manim-style-math/style.json +13 -0
  40. package/skills/aicut-motion/assets/atlas/styles/010-illuminated-manuscript/code.js +1126 -0
  41. package/skills/aicut-motion/assets/atlas/styles/010-illuminated-manuscript/poster.jpg +0 -0
  42. package/skills/aicut-motion/assets/atlas/styles/010-illuminated-manuscript/style.json +13 -0
  43. package/skills/aicut-motion/assets/atlas/styles/011-editorial-essay-collage/code.js +854 -0
  44. package/skills/aicut-motion/assets/atlas/styles/011-editorial-essay-collage/poster.jpg +0 -0
  45. package/skills/aicut-motion/assets/atlas/styles/011-editorial-essay-collage/style.json +13 -0
  46. package/skills/aicut-motion/assets/atlas/styles/012-bioluminescent-deep-sea/code.js +1124 -0
  47. package/skills/aicut-motion/assets/atlas/styles/012-bioluminescent-deep-sea/poster.jpg +0 -0
  48. package/skills/aicut-motion/assets/atlas/styles/012-bioluminescent-deep-sea/style.json +13 -0
  49. package/skills/aicut-motion/assets/atlas/styles/013-product-launch-reveal/code.js +728 -0
  50. package/skills/aicut-motion/assets/atlas/styles/013-product-launch-reveal/poster.jpg +0 -0
  51. package/skills/aicut-motion/assets/atlas/styles/013-product-launch-reveal/style.json +13 -0
  52. package/skills/aicut-motion/assets/atlas/styles/014-halftone-pop-panel/code.js +664 -0
  53. package/skills/aicut-motion/assets/atlas/styles/014-halftone-pop-panel/poster.jpg +0 -0
  54. package/skills/aicut-motion/assets/atlas/styles/014-halftone-pop-panel/style.json +13 -0
  55. package/skills/aicut-motion/assets/atlas/styles/015-isometric-pastel/code.js +991 -0
  56. package/skills/aicut-motion/assets/atlas/styles/015-isometric-pastel/poster.jpg +0 -0
  57. package/skills/aicut-motion/assets/atlas/styles/015-isometric-pastel/style.json +13 -0
  58. package/skills/aicut-motion/assets/atlas/styles/016-oscilloscope-vector-art/code.js +801 -0
  59. package/skills/aicut-motion/assets/atlas/styles/016-oscilloscope-vector-art/poster.jpg +0 -0
  60. package/skills/aicut-motion/assets/atlas/styles/016-oscilloscope-vector-art/style.json +13 -0
  61. package/skills/aicut-motion/assets/atlas/styles/017-risograph-zine/code.js +692 -0
  62. package/skills/aicut-motion/assets/atlas/styles/017-risograph-zine/poster.jpg +0 -0
  63. package/skills/aicut-motion/assets/atlas/styles/017-risograph-zine/style.json +13 -0
  64. package/skills/aicut-motion/assets/atlas/styles/018-claymation-set/code.js +756 -0
  65. package/skills/aicut-motion/assets/atlas/styles/018-claymation-set/poster.jpg +0 -0
  66. package/skills/aicut-motion/assets/atlas/styles/018-claymation-set/style.json +13 -0
  67. package/skills/aicut-motion/assets/atlas/styles/019-neon-sign-at-night/code.js +922 -0
  68. package/skills/aicut-motion/assets/atlas/styles/019-neon-sign-at-night/poster.jpg +0 -0
  69. package/skills/aicut-motion/assets/atlas/styles/019-neon-sign-at-night/style.json +13 -0
  70. package/skills/aicut-motion/assets/atlas/styles/020-kawaii-anime/code.js +852 -0
  71. package/skills/aicut-motion/assets/atlas/styles/020-kawaii-anime/poster.jpg +0 -0
  72. package/skills/aicut-motion/assets/atlas/styles/020-kawaii-anime/style.json +13 -0
  73. package/skills/aicut-motion/assets/atlas/styles/021-ukiyo-e-woodblock/code.js +724 -0
  74. package/skills/aicut-motion/assets/atlas/styles/021-ukiyo-e-woodblock/poster.jpg +0 -0
  75. package/skills/aicut-motion/assets/atlas/styles/021-ukiyo-e-woodblock/style.json +13 -0
  76. package/skills/aicut-motion/assets/atlas/styles/022-16-bit-pixel-odyssey/code.js +793 -0
  77. package/skills/aicut-motion/assets/atlas/styles/022-16-bit-pixel-odyssey/poster.jpg +0 -0
  78. package/skills/aicut-motion/assets/atlas/styles/022-16-bit-pixel-odyssey/style.json +13 -0
  79. package/skills/aicut-motion/assets/atlas/styles/023-chalkboard-lesson/code.js +846 -0
  80. package/skills/aicut-motion/assets/atlas/styles/023-chalkboard-lesson/poster.jpg +0 -0
  81. package/skills/aicut-motion/assets/atlas/styles/023-chalkboard-lesson/style.json +13 -0
  82. package/skills/aicut-motion/assets/atlas/styles/024-cut-paper-diorama/code.js +1008 -0
  83. package/skills/aicut-motion/assets/atlas/styles/024-cut-paper-diorama/poster.jpg +0 -0
  84. package/skills/aicut-motion/assets/atlas/styles/024-cut-paper-diorama/style.json +13 -0
  85. package/skills/aicut-motion/assets/atlas/styles/025-cathedral-glass/code.js +680 -0
  86. package/skills/aicut-motion/assets/atlas/styles/025-cathedral-glass/poster.jpg +0 -0
  87. package/skills/aicut-motion/assets/atlas/styles/025-cathedral-glass/style.json +13 -0
  88. package/skills/aicut-motion/assets/atlas/styles/026-editorial-chart/code.js +633 -0
  89. package/skills/aicut-motion/assets/atlas/styles/026-editorial-chart/poster.jpg +0 -0
  90. package/skills/aicut-motion/assets/atlas/styles/026-editorial-chart/style.json +13 -0
  91. package/skills/aicut-motion/assets/atlas/styles/027-synthwave-outrun/code.js +757 -0
  92. package/skills/aicut-motion/assets/atlas/styles/027-synthwave-outrun/poster.jpg +0 -0
  93. package/skills/aicut-motion/assets/atlas/styles/027-synthwave-outrun/style.json +13 -0
  94. package/skills/aicut-motion/assets/atlas/styles/028-origami-studio/code.js +828 -0
  95. package/skills/aicut-motion/assets/atlas/styles/028-origami-studio/poster.jpg +0 -0
  96. package/skills/aicut-motion/assets/atlas/styles/028-origami-studio/style.json +13 -0
  97. package/skills/aicut-motion/assets/atlas/styles/029-linocut-relief-print/code.js +697 -0
  98. package/skills/aicut-motion/assets/atlas/styles/029-linocut-relief-print/poster.jpg +0 -0
  99. package/skills/aicut-motion/assets/atlas/styles/029-linocut-relief-print/style.json +13 -0
  100. package/skills/aicut-motion/assets/atlas/styles/030-holographic-foil-card/code.js +687 -0
  101. package/skills/aicut-motion/assets/atlas/styles/030-holographic-foil-card/poster.jpg +0 -0
  102. package/skills/aicut-motion/assets/atlas/styles/030-holographic-foil-card/style.json +13 -0
  103. package/skills/aicut-motion/assets/atlas/styles/031-voxel-diorama/code.js +727 -0
  104. package/skills/aicut-motion/assets/atlas/styles/031-voxel-diorama/poster.jpg +0 -0
  105. package/skills/aicut-motion/assets/atlas/styles/031-voxel-diorama/style.json +13 -0
  106. package/skills/aicut-motion/assets/atlas/styles/032-sumi-e-ink-wash/code.js +903 -0
  107. package/skills/aicut-motion/assets/atlas/styles/032-sumi-e-ink-wash/poster.jpg +0 -0
  108. package/skills/aicut-motion/assets/atlas/styles/032-sumi-e-ink-wash/style.json +13 -0
  109. package/skills/aicut-motion/assets/atlas/styles/033-etch-a-sketch-toy/code.js +662 -0
  110. package/skills/aicut-motion/assets/atlas/styles/033-etch-a-sketch-toy/poster.jpg +0 -0
  111. package/skills/aicut-motion/assets/atlas/styles/033-etch-a-sketch-toy/style.json +13 -0
  112. package/skills/aicut-motion/assets/atlas/styles/034-cosmic-star-chart/code.js +951 -0
  113. package/skills/aicut-motion/assets/atlas/styles/034-cosmic-star-chart/poster.jpg +0 -0
  114. package/skills/aicut-motion/assets/atlas/styles/034-cosmic-star-chart/style.json +13 -0
  115. package/skills/aicut-motion/assets/atlas/styles/035-punk-zine-collage/code.js +759 -0
  116. package/skills/aicut-motion/assets/atlas/styles/035-punk-zine-collage/poster.jpg +0 -0
  117. package/skills/aicut-motion/assets/atlas/styles/035-punk-zine-collage/style.json +13 -0
  118. package/skills/aicut-motion/assets/atlas/styles/036-thermal-camera/code.js +738 -0
  119. package/skills/aicut-motion/assets/atlas/styles/036-thermal-camera/poster.jpg +0 -0
  120. package/skills/aicut-motion/assets/atlas/styles/036-thermal-camera/style.json +13 -0
  121. package/skills/aicut-motion/assets/atlas/styles/037-engineering-blueprint/code.js +793 -0
  122. package/skills/aicut-motion/assets/atlas/styles/037-engineering-blueprint/poster.jpg +0 -0
  123. package/skills/aicut-motion/assets/atlas/styles/037-engineering-blueprint/style.json +13 -0
  124. package/skills/aicut-motion/assets/atlas/styles/038-impasto-night/code.js +673 -0
  125. package/skills/aicut-motion/assets/atlas/styles/038-impasto-night/poster.jpg +0 -0
  126. package/skills/aicut-motion/assets/atlas/styles/038-impasto-night/style.json +13 -0
  127. package/skills/aicut-motion/assets/atlas/styles/039-win95-desktop/code.js +907 -0
  128. package/skills/aicut-motion/assets/atlas/styles/039-win95-desktop/poster.jpg +0 -0
  129. package/skills/aicut-motion/assets/atlas/styles/039-win95-desktop/style.json +13 -0
  130. package/skills/aicut-motion/assets/atlas/styles/040-low-poly-faceted/code.js +833 -0
  131. package/skills/aicut-motion/assets/atlas/styles/040-low-poly-faceted/poster.jpg +0 -0
  132. package/skills/aicut-motion/assets/atlas/styles/040-low-poly-faceted/style.json +13 -0
  133. package/skills/aicut-motion/assets/atlas/styles/041-manga-page/code.js +845 -0
  134. package/skills/aicut-motion/assets/atlas/styles/041-manga-page/poster.jpg +0 -0
  135. package/skills/aicut-motion/assets/atlas/styles/041-manga-page/style.json +13 -0
  136. package/skills/aicut-motion/assets/atlas/styles/042-wood-type-letterpress/code.js +496 -0
  137. package/skills/aicut-motion/assets/atlas/styles/042-wood-type-letterpress/poster.jpg +0 -0
  138. package/skills/aicut-motion/assets/atlas/styles/042-wood-type-letterpress/style.json +13 -0
  139. package/skills/aicut-motion/assets/atlas/styles/043-light-painting/code.js +635 -0
  140. package/skills/aicut-motion/assets/atlas/styles/043-light-painting/poster.jpg +0 -0
  141. package/skills/aicut-motion/assets/atlas/styles/043-light-painting/style.json +13 -0
  142. package/skills/aicut-motion/assets/atlas/styles/044-felt-patchwork/code.js +799 -0
  143. package/skills/aicut-motion/assets/atlas/styles/044-felt-patchwork/poster.jpg +0 -0
  144. package/skills/aicut-motion/assets/atlas/styles/044-felt-patchwork/style.json +13 -0
  145. package/skills/aicut-motion/assets/atlas/styles/045-phosphor-terminal/code.js +547 -0
  146. package/skills/aicut-motion/assets/atlas/styles/045-phosphor-terminal/poster.jpg +0 -0
  147. package/skills/aicut-motion/assets/atlas/styles/045-phosphor-terminal/style.json +13 -0
  148. package/skills/aicut-motion/assets/atlas/styles/046-glassmorphism-ui/code.js +592 -0
  149. package/skills/aicut-motion/assets/atlas/styles/046-glassmorphism-ui/poster.jpg +0 -0
  150. package/skills/aicut-motion/assets/atlas/styles/046-glassmorphism-ui/style.json +13 -0
  151. package/skills/aicut-motion/assets/atlas/styles/047-tarot-card/code.js +768 -0
  152. package/skills/aicut-motion/assets/atlas/styles/047-tarot-card/poster.jpg +0 -0
  153. package/skills/aicut-motion/assets/atlas/styles/047-tarot-card/style.json +13 -0
  154. package/skills/aicut-motion/assets/atlas/styles/048-transit-map/code.js +666 -0
  155. package/skills/aicut-motion/assets/atlas/styles/048-transit-map/poster.jpg +0 -0
  156. package/skills/aicut-motion/assets/atlas/styles/048-transit-map/style.json +13 -0
  157. package/skills/aicut-motion/assets/atlas/styles/049-gouache-travel-poster/code.js +559 -0
  158. package/skills/aicut-motion/assets/atlas/styles/049-gouache-travel-poster/poster.jpg +0 -0
  159. package/skills/aicut-motion/assets/atlas/styles/049-gouache-travel-poster/style.json +13 -0
  160. package/skills/aicut-motion/assets/atlas/styles/050-napkin-sketch/code.js +943 -0
  161. package/skills/aicut-motion/assets/atlas/styles/050-napkin-sketch/poster.jpg +0 -0
  162. package/skills/aicut-motion/assets/atlas/styles/050-napkin-sketch/style.json +13 -0
  163. package/skills/aicut-motion/assets/atlas/styles/051-art-deco-foil/code.js +606 -0
  164. package/skills/aicut-motion/assets/atlas/styles/051-art-deco-foil/poster.jpg +0 -0
  165. package/skills/aicut-motion/assets/atlas/styles/051-art-deco-foil/style.json +13 -0
  166. package/skills/aicut-motion/assets/atlas/styles/052-radiograph-on-lightbox/code.js +730 -0
  167. package/skills/aicut-motion/assets/atlas/styles/052-radiograph-on-lightbox/poster.jpg +0 -0
  168. package/skills/aicut-motion/assets/atlas/styles/052-radiograph-on-lightbox/style.json +13 -0
  169. package/skills/aicut-motion/assets/atlas/styles/053-vaporwave/code.js +782 -0
  170. package/skills/aicut-motion/assets/atlas/styles/053-vaporwave/poster.jpg +0 -0
  171. package/skills/aicut-motion/assets/atlas/styles/053-vaporwave/style.json +13 -0
  172. package/skills/aicut-motion/assets/atlas/styles/054-ebru-paper-marbling/code.js +504 -0
  173. package/skills/aicut-motion/assets/atlas/styles/054-ebru-paper-marbling/poster.jpg +0 -0
  174. package/skills/aicut-motion/assets/atlas/styles/054-ebru-paper-marbling/style.json +13 -0
  175. package/skills/aicut-motion/assets/atlas/styles/055-isotype-pictograms/code.js +517 -0
  176. package/skills/aicut-motion/assets/atlas/styles/055-isotype-pictograms/poster.jpg +0 -0
  177. package/skills/aicut-motion/assets/atlas/styles/055-isotype-pictograms/style.json +13 -0
  178. package/skills/aicut-motion/assets/atlas/styles/056-soft-3d-clay/code.js +713 -0
  179. package/skills/aicut-motion/assets/atlas/styles/056-soft-3d-clay/poster.jpg +0 -0
  180. package/skills/aicut-motion/assets/atlas/styles/056-soft-3d-clay/style.json +13 -0
  181. package/skills/aicut-motion/assets/atlas/styles/057-cross-stitch-sampler/code.js +717 -0
  182. package/skills/aicut-motion/assets/atlas/styles/057-cross-stitch-sampler/poster.jpg +0 -0
  183. package/skills/aicut-motion/assets/atlas/styles/057-cross-stitch-sampler/style.json +13 -0
  184. package/skills/aicut-motion/assets/atlas/styles/058-constructivist-propaganda/code.js +540 -0
  185. package/skills/aicut-motion/assets/atlas/styles/058-constructivist-propaganda/poster.jpg +0 -0
  186. package/skills/aicut-motion/assets/atlas/styles/058-constructivist-propaganda/style.json +13 -0
  187. package/skills/aicut-motion/assets/atlas/styles/059-pocket-monochrome/code.js +524 -0
  188. package/skills/aicut-motion/assets/atlas/styles/059-pocket-monochrome/poster.jpg +0 -0
  189. package/skills/aicut-motion/assets/atlas/styles/059-pocket-monochrome/style.json +13 -0
  190. package/skills/aicut-motion/assets/atlas/styles/060-botanical-plate/code.js +934 -0
  191. package/skills/aicut-motion/assets/atlas/styles/060-botanical-plate/poster.jpg +0 -0
  192. package/skills/aicut-motion/assets/atlas/styles/060-botanical-plate/style.json +13 -0
  193. package/skills/aicut-motion/assets/atlas/styles/061-kinetic-type/code.js +690 -0
  194. package/skills/aicut-motion/assets/atlas/styles/061-kinetic-type/poster.jpg +0 -0
  195. package/skills/aicut-motion/assets/atlas/styles/061-kinetic-type/style.json +13 -0
  196. package/skills/aicut-motion/assets/atlas/styles/062-byzantine-mosaic/code.js +612 -0
  197. package/skills/aicut-motion/assets/atlas/styles/062-byzantine-mosaic/poster.jpg +0 -0
  198. package/skills/aicut-motion/assets/atlas/styles/062-byzantine-mosaic/style.json +13 -0
  199. package/skills/aicut-motion/assets/atlas/styles/063-y2k-liquid-chrome/code.js +666 -0
  200. package/skills/aicut-motion/assets/atlas/styles/063-y2k-liquid-chrome/poster.jpg +0 -0
  201. package/skills/aicut-motion/assets/atlas/styles/063-y2k-liquid-chrome/style.json +13 -0
  202. package/skills/aicut-motion/assets/atlas/styles/064-sticky-note-wall/code.js +651 -0
  203. package/skills/aicut-motion/assets/atlas/styles/064-sticky-note-wall/poster.jpg +0 -0
  204. package/skills/aicut-motion/assets/atlas/styles/064-sticky-note-wall/style.json +13 -0
  205. package/skills/aicut-motion/assets/atlas/styles/065-vintage-newsprint/code.js +656 -0
  206. package/skills/aicut-motion/assets/atlas/styles/065-vintage-newsprint/poster.jpg +0 -0
  207. package/skills/aicut-motion/assets/atlas/styles/065-vintage-newsprint/style.json +13 -0
  208. package/skills/aicut-motion/assets/atlas/styles/066-hidden-line-wireframe/code.js +672 -0
  209. package/skills/aicut-motion/assets/atlas/styles/066-hidden-line-wireframe/poster.jpg +0 -0
  210. package/skills/aicut-motion/assets/atlas/styles/066-hidden-line-wireframe/style.json +13 -0
  211. package/skills/aicut-motion/assets/atlas/styles/067-memphis-group/code.js +548 -0
  212. package/skills/aicut-motion/assets/atlas/styles/067-memphis-group/poster.jpg +0 -0
  213. package/skills/aicut-motion/assets/atlas/styles/067-memphis-group/style.json +13 -0
  214. package/skills/aicut-motion/assets/atlas/styles/068-ballpoint-notebook/code.js +989 -0
  215. package/skills/aicut-motion/assets/atlas/styles/068-ballpoint-notebook/poster.jpg +0 -0
  216. package/skills/aicut-motion/assets/atlas/styles/068-ballpoint-notebook/style.json +13 -0
  217. package/skills/aicut-motion/assets/atlas/styles/069-op-art-sphere/code.js +440 -0
  218. package/skills/aicut-motion/assets/atlas/styles/069-op-art-sphere/poster.jpg +0 -0
  219. package/skills/aicut-motion/assets/atlas/styles/069-op-art-sphere/style.json +13 -0
  220. package/skills/aicut-motion/assets/atlas/styles/070-topographic-survey/code.js +895 -0
  221. package/skills/aicut-motion/assets/atlas/styles/070-topographic-survey/poster.jpg +0 -0
  222. package/skills/aicut-motion/assets/atlas/styles/070-topographic-survey/style.json +13 -0
  223. package/skills/aicut-motion/assets/atlas/styles/071-pointillist-afternoon/code.js +563 -0
  224. package/skills/aicut-motion/assets/atlas/styles/071-pointillist-afternoon/poster.jpg +0 -0
  225. package/skills/aicut-motion/assets/atlas/styles/071-pointillist-afternoon/style.json +13 -0
  226. package/skills/aicut-motion/assets/atlas/styles/072-vector-arcade-1980/code.js +627 -0
  227. package/skills/aicut-motion/assets/atlas/styles/072-vector-arcade-1980/poster.jpg +0 -0
  228. package/skills/aicut-motion/assets/atlas/styles/072-vector-arcade-1980/style.json +13 -0
  229. package/skills/aicut-motion/assets/atlas/styles/073-patent-drawing/code.js +1096 -0
  230. package/skills/aicut-motion/assets/atlas/styles/073-patent-drawing/poster.jpg +0 -0
  231. package/skills/aicut-motion/assets/atlas/styles/073-patent-drawing/style.json +13 -0
  232. package/skills/aicut-motion/assets/atlas/styles/074-bauhaus-poster/code.js +595 -0
  233. package/skills/aicut-motion/assets/atlas/styles/074-bauhaus-poster/poster.jpg +0 -0
  234. package/skills/aicut-motion/assets/atlas/styles/074-bauhaus-poster/style.json +13 -0
  235. package/skills/aicut-motion/assets/atlas/styles/075-bitmap-paint-doodle/code.js +665 -0
  236. package/skills/aicut-motion/assets/atlas/styles/075-bitmap-paint-doodle/poster.jpg +0 -0
  237. package/skills/aicut-motion/assets/atlas/styles/075-bitmap-paint-doodle/style.json +13 -0
  238. package/skills/aicut-motion/assets/atlas/styles/076-nail-thread-string-art/code.js +645 -0
  239. package/skills/aicut-motion/assets/atlas/styles/076-nail-thread-string-art/poster.jpg +0 -0
  240. package/skills/aicut-motion/assets/atlas/styles/076-nail-thread-string-art/style.json +13 -0
  241. package/skills/aicut-motion/assets/atlas/styles/077-ridgeline/code.js +436 -0
  242. package/skills/aicut-motion/assets/atlas/styles/077-ridgeline/poster.jpg +0 -0
  243. package/skills/aicut-motion/assets/atlas/styles/077-ridgeline/style.json +13 -0
  244. package/skills/aicut-motion/assets/atlas/styles/078-sketchbook-graphite/code.js +1237 -0
  245. package/skills/aicut-motion/assets/atlas/styles/078-sketchbook-graphite/poster.jpg +0 -0
  246. package/skills/aicut-motion/assets/atlas/styles/078-sketchbook-graphite/style.json +13 -0
  247. package/skills/aicut-motion/assets/atlas/styles/079-teletext-page/code.js +622 -0
  248. package/skills/aicut-motion/assets/atlas/styles/079-teletext-page/poster.jpg +0 -0
  249. package/skills/aicut-motion/assets/atlas/styles/079-teletext-page/style.json +13 -0
  250. package/skills/aicut-motion/assets/atlas/styles/080-silkscreen-grid/code.js +524 -0
  251. package/skills/aicut-motion/assets/atlas/styles/080-silkscreen-grid/poster.jpg +0 -0
  252. package/skills/aicut-motion/assets/atlas/styles/080-silkscreen-grid/style.json +13 -0
  253. package/skills/aicut-motion/assets/atlas/styles/081-guilloch-security-print/code.js +689 -0
  254. package/skills/aicut-motion/assets/atlas/styles/081-guilloch-security-print/poster.jpg +0 -0
  255. package/skills/aicut-motion/assets/atlas/styles/081-guilloch-security-print/style.json +13 -0
  256. package/skills/aicut-motion/assets/atlas/styles/082-ascii-demoscene/code.js +574 -0
  257. package/skills/aicut-motion/assets/atlas/styles/082-ascii-demoscene/poster.jpg +0 -0
  258. package/skills/aicut-motion/assets/atlas/styles/082-ascii-demoscene/style.json +13 -0
  259. package/skills/aicut-motion/assets/atlas/styles/083-international-typographic-style/code.js +469 -0
  260. package/skills/aicut-motion/assets/atlas/styles/083-international-typographic-style/poster.jpg +0 -0
  261. package/skills/aicut-motion/assets/atlas/styles/083-international-typographic-style/style.json +13 -0
  262. package/skills/aicut-motion/assets/atlas/styles/084-flow-field/code.js +531 -0
  263. package/skills/aicut-motion/assets/atlas/styles/084-flow-field/poster.jpg +0 -0
  264. package/skills/aicut-motion/assets/atlas/styles/084-flow-field/style.json +13 -0
  265. package/skills/aicut-motion/assets/atlas/styles/085-macpaint-1984/code.js +675 -0
  266. package/skills/aicut-motion/assets/atlas/styles/085-macpaint-1984/poster.jpg +0 -0
  267. package/skills/aicut-motion/assets/atlas/styles/085-macpaint-1984/style.json +13 -0
  268. package/skills/aicut-motion/assets/atlas/styles/086-multi-scale-truchet/code.js +609 -0
  269. package/skills/aicut-motion/assets/atlas/styles/086-multi-scale-truchet/poster.jpg +0 -0
  270. package/skills/aicut-motion/assets/atlas/styles/086-multi-scale-truchet/style.json +13 -0
  271. package/skills/aicut-motion/references/design-systems/README.md +1 -1
  272. package/skills/aicut-motion/references/motion-delivery.md +55 -0
  273. package/skills/aicut-motion/references/pages.md +1 -1
  274. package/skills/aicut-motion/references/style-index.json +690 -0
  275. package/skills/aicut-motion/references/style-research.md +73 -0
  276. package/skills/aicut-motion/references/style-selection.md +71 -0
  277. package/skills/aicut-motion/scripts/atlas-viewer.html +195 -0
  278. package/skills/aicut-motion/scripts/atlas.mjs +109 -0
  279. package/studio/client.mjs +3 -3
  280. package/studio/server/fetch-github.mjs +14 -3
  281. package/studio/server/server.mjs +71 -6
  282. package/studio/server/skill-summaries.mjs +60 -0
  283. package/studio/server/skills.mjs +121 -7
  284. package/studio/server/styles-store.mjs +235 -0
  285. package/studio/server/template-posters.mjs +2 -2
  286. package/studio/server/templates-page.mjs +93 -93
  287. package/studio/server/templates.mjs +32 -7
  288. package/studio/ui/dist/assets/ExportCenter-DasulhAv.js +1 -0
  289. package/studio/ui/dist/assets/SettingsModal-BZw0Hz2_.js +2 -0
  290. package/studio/ui/dist/assets/apple-touch-icon-ClxQ7j-O.png +0 -0
  291. package/studio/ui/dist/assets/es-C8XPZARI.js +1 -0
  292. package/studio/ui/dist/assets/favicon-Blwx8Trs.png +0 -0
  293. package/studio/ui/dist/assets/index-BjJVmBzB.js +1623 -0
  294. package/studio/ui/dist/assets/index-C3BfKZFO.css +1 -0
  295. package/studio/ui/dist/assets/ja-BeNkdaEj.js +1 -0
  296. package/studio/ui/dist/assets/ko-DcTVhdzK.js +1 -0
  297. package/studio/ui/dist/assets/zh-CN-Cg51ctbL.js +1 -0
  298. package/studio/ui/dist/index.html +4 -3
  299. package/studio/ui/dist/assets/ExportCenter-F-2vF-lQ.js +0 -1
  300. package/studio/ui/dist/assets/SettingsModal-BgVYguNu.js +0 -2
  301. package/studio/ui/dist/assets/es-BRUzvuoM.js +0 -1
  302. package/studio/ui/dist/assets/index-Bhg-9dA3.css +0 -1
  303. package/studio/ui/dist/assets/index-CWur1Iw9.js +0 -1625
  304. package/studio/ui/dist/assets/ja-Cth-uDcW.js +0 -1
  305. package/studio/ui/dist/assets/ko-upvw591D.js +0 -1
  306. package/studio/ui/dist/assets/zh-CN-BCfJFazB.js +0 -1
@@ -0,0 +1,13 @@
1
+ {
2
+ "id": 76,
3
+ "name": "Nail & Thread String Art",
4
+ "nameZh": "钉线绕线艺术",
5
+ "family": "Generative & Type",
6
+ "familyZh": "生成艺术与字体",
7
+ "description": "Taut cotton threads strung between brass nails on a stained walnut board; every curve is an envelope of straight chords, with thread translucency, sheen and cast shadows, plus pyrography lettering.",
8
+ "motionNotes": "Motion: Nails are tapped in around the outline, then thread is wound chord by chord so the glowing envelopes emerge, the filament and base are laced, the rays snap taut, and the title is burned in with a travelling ember while the camera slowly pushes in.",
9
+ "explainerNotes": "Explainer: The network is literally strung on the board — nails are neurons, a weight is how many wraps of thread a connection has — and learning is re-winding; the camera travels along one long walnut board between scenes, labels are kraft tags nailed on, arrows are threads with nail barbs, counters are nail-and-thread 7-segment digits, and emphasis is a red thread wound round a ring of nails.",
10
+ "code": "code.js",
11
+ "registeredAs": "string-art",
12
+ "source": "https://www.futurepedia.io/resources/ai-style-atlas/view"
13
+ }
@@ -0,0 +1,436 @@
1
+ {
2
+ // Stacked ridgeline in the manner of the famous pulsar plot: occluding white traces on black.
3
+ // ---- print finish: the original is an offset print, cream ink on rough black stock ----
4
+ // cached per pixel size: ink-density mottle (multiply) and warm stock fibres (added light)
5
+ const RL = {};
6
+ const rlTex = (pw, ph) => {
7
+ const key = pw + 'x' + ph; if (RL.key === key) return RL;
8
+ RL.key = key; RL.half = H.layer(pw >> 1, ph >> 1); RL.quarter = H.layer(pw >> 2, ph >> 2);
9
+ // ink mottle: cream areas print 82-100% dense, blotchy at two scales (black stays black under multiply)
10
+ const mw = 320, mh = 180, m = H.layer(mw, mh), mx = m.getContext('2d'), mi = mx.createImageData(mw, mh), nz = H.makeNoise(4242);
11
+ for (let y = 0; y < mh; y++) for (let x = 0; x < mw; x++) {
12
+ const v = 0.5 + 0.5 * nz.fbm2(x * 0.045, y * 0.045, 4), f = 0.5 + 0.5 * nz.n2(x * 0.6, y * 0.6), d = 1 - 0.13 * v - 0.06 * f, i = (y * mw + x) * 4;
13
+ mi.data[i] = 255 * d; mi.data[i + 1] = 255 * (d - 0.01); mi.data[i + 2] = 255 * (d - 0.03); mi.data[i + 3] = 255;
14
+ }
15
+ mx.putImageData(mi, 0, 0);
16
+ RL.ink = H.layer(pw, ph); { const g = RL.ink.getContext('2d'); g.imageSmoothingQuality = 'high'; g.drawImage(m, 0, 0, pw, ph); }
17
+ // stock: a warm lift with cloudy variation plus sparse light fibres, added with 'lighter'
18
+ const sw = 256, sh = 144, s = H.layer(sw, sh), sx = s.getContext('2d'), si = sx.createImageData(sw, sh), nz2 = H.makeNoise(515);
19
+ for (let y = 0; y < sh; y++) for (let x = 0; x < sw; x++) {
20
+ const v = 0.5 + 0.5 * nz2.fbm2(x * 0.03, y * 0.03, 4), i = (y * sw + x) * 4;
21
+ si.data[i] = 5 + 6 * v; si.data[i + 1] = 4 + 5 * v; si.data[i + 2] = 2 + 3 * v; si.data[i + 3] = 255;
22
+ }
23
+ sx.putImageData(si, 0, 0);
24
+ RL.stock = H.layer(pw, ph); const g = RL.stock.getContext('2d'); g.fillStyle = '#000'; g.fillRect(0, 0, pw, ph); g.imageSmoothingQuality = 'high'; g.drawImage(s, 0, 0, pw, ph);
25
+ const r = H.rng(77), k = pw / 1280; g.lineCap = 'round';
26
+ for (let i = 0; i < 900; i++) {
27
+ const x = r() * pw, y = r() * ph, a = r() * Math.PI * 2, l = r.range(3, 14) * k, c = r.range(8, 20) | 0;
28
+ g.strokeStyle = `rgb(${c},${c - 2},${c - 5})`; g.lineWidth = r.range(0.4, 1) * k;
29
+ g.beginPath(); g.moveTo(x, y); g.quadraticCurveTo(x + Math.cos(a + 0.6) * l * 0.5, y + Math.sin(a + 0.6) * l * 0.5, x + Math.cos(a) * l, y + Math.sin(a) * l); g.stroke();
30
+ }
31
+ RL.inkD = RL.ink.getContext('2d').getImageData(0, 0, pw, ph).data; RL.stockD = g.getImageData(0, 0, pw, ph).data;
32
+ RL.ink = RL.stock = null;
33
+ return RL;
34
+ };
35
+ const printFinish = (ctx, grain, seed) => {
36
+ const cv = ctx.canvas, pw = cv.width, ph = cv.height, T = rlTex(pw, ph);
37
+ // soft copies made by resampling (half res ~ 1px spread, quarter res ~ 2.5px halo): far cheaper than ctx.filter blur
38
+ const hx = T.half.getContext('2d'), qx = T.quarter.getContext('2d');
39
+ hx.imageSmoothingQuality = 'medium'; hx.drawImage(cv, 0, 0, T.half.width, T.half.height);
40
+ qx.imageSmoothingQuality = 'medium'; qx.drawImage(T.half, 0, 0, T.quarter.width, T.quarter.height);
41
+ ctx.save(); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.imageSmoothingEnabled = true; ctx.imageSmoothingQuality = 'medium';
42
+ // ink spread: a soft copy of the lines added back, so the cream bleeds a hair into the stock
43
+ ctx.globalCompositeOperation = 'lighter'; ctx.globalAlpha = 0.22; ctx.drawImage(T.half, 0, 0, pw, ph);
44
+ ctx.globalAlpha = 0.07; ctx.drawImage(T.quarter, 0, 0, pw, ph);
45
+ ctx.restore();
46
+ // one pixel pass: ink density (multiply) + warm stock (add) + mono film/print grain (as H.grain)
47
+ const img = ctx.getImageData(0, 0, pw, ph), d = img.data, ink = T.inkD, st = T.stockD, r = H.rng(seed), ka = grain * 255, inv = 1 / 255;
48
+ for (let i = 0; i < d.length; i += 4) {
49
+ const n = (r() - 0.5) * ka;
50
+ d[i] = d[i] * ink[i] * inv + st[i] + n; d[i + 1] = d[i + 1] * ink[i + 1] * inv + st[i + 1] + n; d[i + 2] = d[i + 2] * ink[i + 2] * inv + st[i + 2] + n;
51
+ }
52
+ ctx.putImageData(img, 0, 0);
53
+ };
54
+ registerStyle({
55
+ id: 'ridgeline',
56
+ name: 'Ridgeline',
57
+ category: 'Data & Information',
58
+ description: 'Sixty stacked traces of noisy signal, each filled black so it occludes the one behind, drawn as thin white lines in a perfectly centred block with a tiny typographic caption.',
59
+ motion: 'Traces are plotted one after another from the top, each swept left to right like a pen recorder and occluding the ones behind; once the stack is complete the peaks ripple like a live signal and the caption types in.',
60
+ duration: 5,
61
+ fonts: ['400 10px "Space Mono"', '700 10px "Space Mono"', '700 34px "Space Mono"', '400 13px "Space Mono"', '700 18px "Space Mono"', '700 40px "Space Mono"', '700 56px "Space Mono"', '700 84px "Space Mono"', '400 26px "Space Mono"', '700 30px "Space Mono"'],
62
+ frameT: 4.9,
63
+ readsPixels: true,
64
+ draw(ctx, W, H_, t) {
65
+ ctx.fillStyle = '#050505'; ctx.fillRect(0, 0, W, H_);
66
+
67
+ const N = 60, BW = 380, gap = 6.6;
68
+ const x0 = W / 2 - BW / 2, x1 = W / 2 + BW / 2;
69
+ const blockH = gap * (N - 1);
70
+ const yTop = H_ / 2 - blockH / 2 + 4; // optical centre (peaks rise above)
71
+ const nz = H.makeNoise(1919), nz2 = H.makeNoise(67);
72
+ const STEP = 1.5;
73
+ const cxw = W / 2 - 8; // phase of the main pulse
74
+
75
+ ctx.lineJoin = 'round'; ctx.lineCap = 'round';
76
+ for (let i = 0; i < N; i++) {
77
+ const r = H.rng(1000 + i);
78
+ const base = yTop + i * gap;
79
+ // peaks: a few gaussians clustered around the main pulse phase
80
+ const peaks = [];
81
+ const np = r.int(4, 7);
82
+ for (let k = 0; k < np; k++) {
83
+ peaks.push({
84
+ mu: cxw + r.gauss() * 36 + Math.sin(t * 0.9 + i * 0.37 + k) * 3,
85
+ s: r.range(4, 17),
86
+ h: (6 + 52 * Math.pow(r(), 1.7)) * (0.75 + 0.25 * Math.sin(t * 1.3 + i * 0.5 + k * 2)),
87
+ });
88
+ }
89
+ // a quieter side lobe on some lines
90
+ if (r.chance(0.45)) peaks.push({ mu: cxw + r.range(55, 95) * (r.chance(0.5) ? 1 : -1), s: r.range(4, 9), h: r.range(4, 16) });
91
+
92
+ const pts = [];
93
+ for (let x = x0; x <= x1 + 0.01; x += STEP) {
94
+ const u = (x - x0) / BW;
95
+ const env = Math.pow(Math.sin(Math.PI * H.clamp((u - 0.2) / 0.6)), 1.6); // central window
96
+ let a = 0;
97
+ for (const p of peaks) { const d = (x - p.mu) / p.s; a += p.h * Math.exp(-0.5 * d * d); }
98
+ a *= env;
99
+ // fine noise texture: tiny everywhere, larger in the active window
100
+ const fine = nz.n3(x * 0.32, i * 0.9, t * 0.8) * (0.9 + env * 3.2) + nz2.n3(x * 0.06, i * 0.45, t * 0.3) * env * 9;
101
+ pts.push([x, base - Math.max(-2, a + fine)]);
102
+ }
103
+ // pen-recorder sweep: this trace is drawn left to right over 0.24 s
104
+ const sweep = H.clamp((t - (0.15 + i * 0.036)) / 0.24);
105
+ if (sweep <= 0) continue;
106
+ const nDraw = Math.max(2, Math.ceil(pts.length * H.ease.inOut(sweep)));
107
+ const vis = pts.slice(0, nDraw);
108
+ const xe = vis[vis.length - 1][0];
109
+ // occlusion: fill under the trace with black, then stroke
110
+ ctx.beginPath();
111
+ ctx.moveTo(vis[0][0], vis[0][1]);
112
+ for (const p of vis) ctx.lineTo(p[0], p[1]);
113
+ ctx.lineTo(xe, base + gap * 3); ctx.lineTo(x0, base + gap * 3); ctx.closePath();
114
+ ctx.fillStyle = '#050505'; ctx.fill();
115
+ ctx.beginPath();
116
+ ctx.moveTo(vis[0][0], vis[0][1]);
117
+ for (const p of vis) ctx.lineTo(p[0], p[1]);
118
+ ctx.strokeStyle = '#F2F0EA'; ctx.lineWidth = 1.25; ctx.stroke();
119
+ if (sweep < 1) {
120
+ const [hx, hy] = vis[vis.length - 1];
121
+ const gl = ctx.createRadialGradient(hx, hy, 0, hx, hy, 5);
122
+ gl.addColorStop(0, 'rgba(255,255,255,0.6)'); gl.addColorStop(1, 'rgba(255,255,255,0)');
123
+ ctx.fillStyle = gl; ctx.beginPath(); ctx.arc(hx, hy, 5, 0, 7); ctx.fill();
124
+ }
125
+ }
126
+
127
+ // ---- tiny caption ----
128
+ const cy = yTop + blockH + 48;
129
+ const spaced = (str, y, track, font, col) => {
130
+ ctx.font = font; ctx.fillStyle = col; ctx.textAlign = 'left'; ctx.textBaseline = 'alphabetic';
131
+ let w = 0; for (const ch of str) w += ctx.measureText(ch).width + track; w -= track;
132
+ let x = W / 2 - w / 2; for (const ch of str) { ctx.fillText(ch, x, y); x += ctx.measureText(ch).width + track; }
133
+ };
134
+ // caption fades up letter by letter (centred, so full width is reserved)
135
+ const capA = (k, n, t0) => H.clamp((t - t0 - k * (0.5 / n)) / 0.15);
136
+ const spacedReveal = (str, y, track, font, col, t0) => {
137
+ ctx.font = font; ctx.textAlign = 'left'; ctx.textBaseline = 'alphabetic';
138
+ let w = 0; for (const ch of str) w += ctx.measureText(ch).width + track; w -= track;
139
+ let x = W / 2 - w / 2, k = 0;
140
+ for (const ch of str) { ctx.globalAlpha = capA(k++, str.length, t0); ctx.fillStyle = col; ctx.fillText(ch, x, y); x += ctx.measureText(ch).width + track; }
141
+ ctx.globalAlpha = 1;
142
+ };
143
+ spacedReveal('60 CONSECUTIVE FORWARD PASSES', cy, 3.2, '700 10px "Space Mono"', 'rgba(242,240,234,0.82)', 2.6);
144
+ spacedReveal('neuron 4,096 · layer 31 · tokens 1–256', cy + 16, 1.2, '400 10px "Space Mono"', 'rgba(242,240,234,0.42)', 2.9);
145
+
146
+ printFinish(ctx, 0.06, 8 + Math.floor(t * 12));
147
+ },
148
+ // Sound: a chart recorder in a quiet lab. Each trace is plotted with a stylus scratch over a low servo, and
149
+ // the servo bends up as the pen climbs each peak, so the peaks are heard where they are drawn. Labelled pulses
150
+ // on the tape thump past like a slow pulsar (dog low, cat higher); the sixty rounds start as a wobbling,
151
+ // detuned drone that pulls into one clean tone on the cat pitch. Times mirror explainer() below.
152
+ explainerSound(k) {
153
+ const D = 15, io = H.ease.inOut, lin = (u) => u;
154
+ const seg = (t, a, b) => H.clamp((t - a) / (b - a));
155
+ const when = (t0, t1, ease, u) => { for (let i = 0; i <= 400; i++) { const t = t0 + ((t1 - t0) * i) / 400; if (ease(i / 400) >= u - 1e-6) return t; } return t1; };
156
+ const pan = (px) => H.clamp((px / 1280) * 2 - 1, -1, 1) * 0.7;
157
+ const DOG = 196, CAT = 294; // pitch of the "dog" and "cat" positions on the answer axis (G3, D4)
158
+ // a plotted trace: stylus scratch + servo that bends up over each peak as the pen crosses it
159
+ const plot = (t0, t1, ease, peaks, x0, x1, g = 1, minor = false) => {
160
+ const d = t1 - t0, base = 92, f = [[0, base]];
161
+ peaks.slice().sort((a, b) => a.u - b.u).forEach((p) => {
162
+ const tp = when(t0, t1, ease, p.u) - t0, w = Math.max(0.025, d * p.s * 2.2);
163
+ f.push([Math.max(f[f.length - 1][0] + 0.005, tp - w), base], [tp, base * (1 + p.h / 45)], [tp + w, base]);
164
+ if (p.h >= 30) k.tone(t0 + tp, { f: p.cat ? CAT : DOG, dur: 0.35, gain: 0.13 * g, a: 0.006, verb: 0.25, pan: pan(H.lerp(x0, x1, p.u)), minor }); // the peak sounds its pitch
165
+ });
166
+ f.push([d, base]);
167
+ k.tone(t0, { f, type: 'triangle', dur: d + 0.04, gain: 0.035 * g, a: 0.03, hold: d - 0.06, filter: 'lowpass', f2: 700, pan: pan((x0 + x1) / 2), minor });
168
+ k.noise(t0, { dur: d, filter: 'bandpass', f: [[0, 1500], [d * 0.5, 2100], [d, 1500]], q: 1.4, gain: 0.028 * g, a: 0.03, hold: d - 0.06, pan: pan((x0 + x1) / 2), minor: true });
169
+ };
170
+ // a soft low note for labels and captions
171
+ const note = (t, f, g = 1, p = 0, minor = true) => k.tone(t, { f, dur: 0.7, gain: 0.08 * g, a: 0.01, verb: 0.3, pan: p, minor });
172
+ // recorder digit tick
173
+ const tick = (t, g, p) => k.withMinor(() => { k.noise(t, { dur: 0.014, filter: 'bandpass', f: 1800, q: 2, gain: 0.18 * g, a: 0.001, pan: p }); k.tone(t, { f: 150, dur: 0.02, gain: 0.04 * g, pan: p }); });
174
+ const counter = (t0, t1, steps, p) => { let last = -1, lastT = -1; for (let t = t0; t <= t1 + 1e-6; t += 1 / 120) { const v = Math.floor(io(seg(t, t0, t1)) * steps); if (v !== last && t - lastT >= 1 / 12) { tick(t, 0.8 + 0.3 * v / steps, p); last = v; lastT = t; } } };
175
+ const slide = (t0, t1, g = 1) => k.noise(t0, { dur: t1 - t0 + 0.1, color: 'brown', filter: 'bandpass', f: [[0, 220], [(t1 - t0) * 0.5, 420], [t1 - t0 + 0.1, 200]], q: 0.6, gain: 0.12 * g, a: (t1 - t0) * 0.45 });
176
+
177
+ k.bed('room', 0, D, { gain: 0.3 });
178
+ k.bed('hiss', 0, D, { gain: 0.8 });
179
+
180
+ // ---- hook: one big trace sweeps 0 -> 1.4, title and caption, then the title docks (1.6 -> 2.4)
181
+ plot(0, 1.4, io, [{ u: 0.5, s: 0.03, h: 40, cat: true }, { u: 0.44, s: 0.02, h: 18 }], 120, 1160, 1.2);
182
+ note(0.62, 'A3', 0.9); // caption: one signal, read sixty times
183
+ slide(1.6, 2.4, 0.7);
184
+
185
+ // ---- data: the empty stack rules itself, the tape feeds labelled pulses in
186
+ k.noise(2.5, { dur: 0.95, filter: 'bandpass', f: [[0, 900], [0.95, 1400]], q: 1.2, gain: 0.04, a: 0.1, pan: pan(920), minor: true }); // 60 hairlines rule across
187
+ note(3.05, 'D3', 1.1, pan(920)); // "the model"
188
+ k.noise(3.3, { dur: 0.6, filter: 'bandpass', f: [[0, 800], [0.6, 1300]], q: 1.4, gain: 0.04, a: 0.05, pan: pan(920), minor: true }); // arrow into the model
189
+ { // tape pulses (same seeded set as explainer) thump as each passes the arrow at x = 920
190
+ const pr = H.rng(77), P = []; for (let q = 0; q < 14; q++) P.push({ x0: q * 100, cat: pr.chance(0.5), h: pr.range(30, 48) });
191
+ for (const p of P) {
192
+ // PX = ((x0 - (t-2.5)*170) mod 1400) - 60 = 920 -> t = 2.5 + (x0 - 980 + 1400 m) / 170
193
+ for (let m = 0; m < 2; m++) {
194
+ const t = 2.5 + (p.x0 - 980 + 1400 * m) / 170;
195
+ if (t < 2.75 || t > 6.0) continue;
196
+ const g = (p.h / 48) * (1 - seg(t, 5.8, 6.2) * 0.6);
197
+ k.withMinor(() => { k.tone(t, { f: [[0, p.cat ? CAT : DOG], [0.09, (p.cat ? CAT : DOG) * 0.92]], dur: 0.12, gain: 0.12 * g, a: 0.004, pan: pan(920) }); k.noise(t, { dur: 0.015, filter: 'bandpass', f: 1200, q: 1.5, gain: 0.08 * g, a: 0.001, pan: pan(920) }); });
198
+ }
199
+ }
200
+ }
201
+ counter(2.8, 5.8, 30, pan(150));
202
+ k.play('tock', 5.8, { f: 330, gain: 0.45, pan: pan(150) }); // 1,000,000
203
+
204
+ // ---- loop: three magnified traces act out guess / check / adjust
205
+ plot(6.6, 7.2, io, [{ u: 0.36, s: 0.03, h: 46 }, { u: 0.55, s: 0.02, h: 10 }], 260, 1060, 1.3); // guess: peak lands on dog
206
+ // "dog?" ✗ and the scribbled ring: the wrong guess
207
+ k.tone(7.1, { f: 'D3', type: 'triangle', dur: 0.3, gain: 0.16, hold: 0.08, filter: 'lowpass', f2: 800, pan: pan(550) });
208
+ k.tone(7.28, { f: 'A2', type: 'triangle', dur: 0.55, gain: 0.17, hold: 0.12, filter: 'lowpass', f2: 600, pan: pan(550) });
209
+ k.play('stroke', 7.4, { material: 'pen', dur: 0.5, gain: 2.2, pan: pan(550), minor: true }); // ring around the guess
210
+ plot(8.1, 8.7, io, [{ u: 0.36, s: 0.03, h: 46 }, { u: 0.55, s: 0.02, h: 10 }], 260, 1060, 0.9, true); // check: same trace again
211
+ k.tone(8.3, { f: CAT, dur: 0.9, gain: 0.07, a: 0.15, verb: 0.3, pan: pan(770) }); // dashed target fades in on cat
212
+ note(8.35, 'F#3', 0.8, pan(840)); // "answer: cat"
213
+ k.noise(8.6, { dur: 0.4, filter: 'bandpass', f: [[0, 900], [0.4, 1400]], q: 1.4, gain: 0.05, a: 0.04, pan: pan(660), minor: true }); // error arrow
214
+ { // adjust: the trace sweeps 8.9 -> 9.5 while its peak shifts dog -> cat (9.0 -> 9.9); find where the pen meets it
215
+ let tc = 9.5; for (let t = 8.9; t <= 9.5; t += 0.002) { if (io(seg(t, 8.9, 9.5)) >= H.lerp(0.36, 0.64, io(seg(t, 9.0, 9.9)))) { tc = t; break; } }
216
+ const uc = H.lerp(0.36, 0.64, io(seg(tc, 9.0, 9.9)));
217
+ plot(8.9, 9.5, io, [{ u: uc, s: 0.03, h: 50 }], 260, 1060, 1.0);
218
+ // the peak slides over: a slow glide from the dog pitch up to the cat pitch
219
+ k.tone(9.0, { f: [[0, DOG], [0.15, DOG * 1.01], [0.75, CAT * 0.99], [0.9, CAT]], dur: 1.0, gain: 0.09, a: 0.12, hold: 0.6, verb: 0.2, pan: pan(550) });
220
+ }
221
+ note(9.05, 'B2', 0.8, pan(660)); // "shift the weights"
222
+ // "cat" ✓: the correction, cat pitch with its fifth
223
+ k.tone(9.9, { f: CAT, dur: 1.2, gain: 0.14, a: 0.008, verb: 0.35, pan: pan(900) });
224
+ k.tone(9.97, { f: CAT * 1.5, dur: 1.0, gain: 0.09, a: 0.008, verb: 0.35, pan: pan(900) });
225
+ k.noise(10.0, { dur: 0.4, filter: 'bandpass', f: [[0, 900], [0.4, 1300]], q: 1.4, gain: 0.04, a: 0.05, pan: -0.7, minor: true }); // repeat bracket
226
+ slide(10.6, 11.4, 1.0); // camera pulls back to the stack
227
+
228
+ // ---- progress: 57 rounds plot in 11.3 -> 12.78; noisy peaks pull into one clean ridge
229
+ {
230
+ const t0 = 11.3, t1 = 12.8, d = t1 - t0;
231
+ k.noise(t0, { dur: d, filter: 'bandpass', f: [[0, 1600], [d, 2100]], q: 1.2, gain: 0.05, a: 0.1, hold: d - 0.3, pan: 0.05, minor: true }); // the stylus racing down the stack
232
+ // three detuned voices converge on the cat pitch as the ridges align
233
+ [[0.78, -0.4], [1.22, 0.4], [0.93, 0]].forEach(([r, p], i) => k.tone(t0, { f: [[0, CAT * r], [d * 0.5, CAT * (1 + (r - 1) * 0.35)], [d, CAT]], dur: d + 0.2, gain: 0.05, a: 0.2, hold: d - 0.3, pan: p * 0.5, filter: 'lowpass', f2: 900 }));
234
+ // per-round pen pulses, a few audible: every 6th round's cat peak
235
+ for (let i = 3; i < 60; i += 6) { const tp = 11.3 + (i - 3) * 0.026 + 0.22 * 0.64; k.tone(tp, { f: CAT, dur: 0.12, gain: 0.05 + 0.05 * (i / 60), a: 0.004, pan: pan(700), minor: true }); }
236
+ note(11.4, 'D3', 0.7, pan(250)); // "round 1"
237
+ note(12.7, 'D3', 0.7, pan(250)); // "round 60"
238
+ counter(11.3, 12.8, 36, pan(1050));
239
+ }
240
+ // 97% underlined, the bracket "one clean peak: cat", the last trace thickens: the big hit
241
+ k.play('impact', 12.9, { gain: 0.55, pan: pan(1050) });
242
+ k.tone(12.9, { f: CAT, dur: 2.0, gain: 0.17, a: 0.005, verb: 0.4, pan: pan(900) });
243
+ k.tone(12.9, { f: CAT / 2, dur: 2.0, gain: 0.12, a: 0.005, verb: 0.3 });
244
+ k.noise(12.9, { dur: 0.5, filter: 'bandpass', f: [[0, 900], [0.5, 1300]], q: 1.4, gain: 0.04, a: 0.05, pan: pan(1100), minor: true }); // underline draws
245
+ // takeaway fades up: the resolve on cat
246
+ ['D3', 'A3', 'D4', 'F#4'].forEach((f, i) => k.tone(13.45 + i * 0.09, { f, dur: 1.4, gain: 0.09 - i * 0.01, a: 0.015, verb: 0.4, pan: (i - 1.5) * 0.2 }));
247
+ },
248
+ explainerDuration: 15,
249
+ explainerNote: 'Each white trace is one training round: a recorder tape feeds labelled pulses into the empty stack, three magnified traces act out guess / check / adjust (the peak lands on "dog", a dashed target shows "cat", the peak slides over), then the camera pulls back and sixty rounds plot themselves as the noisy peaks align into one clean ridge, captioned in Space Mono.',
250
+ explainer(ctx, W, H_, t) {
251
+ const S = (a, b) => H.clamp((t - a) / (b - a));
252
+ const BGC = '#050505', FG = '#F2F0EA', DIM = 'rgba(242,240,234,0.6)';
253
+ ctx.fillStyle = BGC; ctx.fillRect(0, 0, W, H_);
254
+ const nz = H.makeNoise(1919), nz2 = H.makeNoise(67);
255
+ const mono = (str, x, y, size, weight, col, track, align = 'center', a = 1) => {
256
+ if (a <= 0) return 0; ctx.globalAlpha = a; ctx.font = `${weight} ${size}px "Space Mono"`; ctx.fillStyle = col; ctx.textAlign = 'left'; ctx.textBaseline = 'alphabetic';
257
+ let w = 0; for (const ch of str) w += ctx.measureText(ch).width + track; w -= track;
258
+ let cx = align === 'center' ? x - w / 2 : align === 'right' ? x - w : x;
259
+ for (const ch of str) { ctx.fillText(ch, cx, y); cx += ctx.measureText(ch).width + track; }
260
+ ctx.globalAlpha = 1; return w;
261
+ };
262
+ const arrow = (x0, y0, x1, y1, p, col = FG, lw = 2) => {
263
+ if (p <= 0) return; const ex = H.lerp(x0, x1, p), ey = H.lerp(y0, y1, p);
264
+ ctx.strokeStyle = col; ctx.lineWidth = lw; ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(ex, ey); ctx.stroke();
265
+ if (p > 0.95) { const a = Math.atan2(y1 - y0, x1 - x0); ctx.beginPath(); ctx.moveTo(x1 - Math.cos(a - 0.45) * 12, y1 - Math.sin(a - 0.45) * 12); ctx.lineTo(x1, y1); ctx.lineTo(x1 - Math.cos(a + 0.45) * 12, y1 - Math.sin(a + 0.45) * 12); ctx.stroke(); }
266
+ };
267
+ const trace = (xa, xb, y, k, peaks, noiseAmt, row, sweep = 1, lw = 1.25, col = FG) => {
268
+ if (sweep <= 0) return;
269
+ const pts = [], BWd = xb - xa, n = Math.ceil(BWd / 1.5);
270
+ for (let i = 0; i <= n * sweep; i++) {
271
+ const u = i / n, x = xa + u * BWd;
272
+ const env = Math.pow(Math.sin(Math.PI * H.clamp((u - 0.12) / 0.76)), 1.4);
273
+ let a = 0; for (const p of peaks) { const d = (u - p.u) / p.s; a += p.h * Math.exp(-0.5 * d * d); }
274
+ a = a * env + nz.n3(u * 380 * 0.32, row * 0.9, t * 0.8) * (0.9 + env * 3 * noiseAmt) + nz2.n3(u * 380 * 0.06, row * 0.45, t * 0.3) * env * 9 * noiseAmt;
275
+ pts.push([x, y - Math.max(-2, a) * k]);
276
+ }
277
+ if (pts.length < 2) return pts;
278
+ const xe = pts[pts.length - 1][0];
279
+ ctx.beginPath(); ctx.moveTo(pts[0][0], pts[0][1]); for (const p of pts) ctx.lineTo(p[0], p[1]);
280
+ ctx.lineTo(xe, y + 40 * k); ctx.lineTo(xa, y + 40 * k); ctx.closePath(); ctx.fillStyle = BGC; ctx.fill();
281
+ ctx.beginPath(); ctx.moveTo(pts[0][0], pts[0][1]); for (const p of pts) ctx.lineTo(p[0], p[1]);
282
+ ctx.strokeStyle = col; ctx.lineWidth = lw; ctx.lineJoin = 'round'; ctx.stroke();
283
+ if (sweep < 1) { const [hx, hy] = pts[pts.length - 1]; const g = ctx.createRadialGradient(hx, hy, 0, hx, hy, 7); g.addColorStop(0, 'rgba(255,255,255,0.7)'); g.addColorStop(1, 'rgba(255,255,255,0)'); ctx.fillStyle = g; ctx.beginPath(); ctx.arc(hx, hy, 7, 0, 7); ctx.fill(); }
284
+ return pts;
285
+ };
286
+ const U_DOG = 0.36, U_CAT = 0.64;
287
+ // explainer stack: bigger than the still so it fills the video frame
288
+ const N = 60, gap = 7.6, SX0 = 330, SX1 = 910, SK = 1.35, STOP = 140;
289
+ const rowPeaks = (i) => {
290
+ const r = H.rng(1000 + i), c = Math.pow(i / (N - 1), 0.8), pk = [];
291
+ const np = Math.round(H.lerp(5, 0, c));
292
+ for (let k = 0; k < np; k++) pk.push({ u: r.range(0.25, 0.75), s: r.range(0.012, 0.04), h: r.range(6, 40) * (1 - c) });
293
+ pk.push({ u: U_DOG + r.gauss() * 0.01, s: 0.03, h: 40 * (1 - c) * r.range(0.5, 1) });
294
+ pk.push({ u: U_CAT + r.gauss() * 0.012 * (1 - c), s: H.lerp(0.035, 0.022, c), h: H.lerp(15, 62, c) * r.range(0.85, 1.0) });
295
+ return pk;
296
+ };
297
+
298
+ // ================= HOOK =================
299
+ if (t < 2.6) {
300
+ ctx.globalAlpha = 1 - S(2.0, 2.5);
301
+ trace(120, 1160, 520, 3.0, [{ u: 0.5, s: 0.03, h: 40 }, { u: 0.44, s: 0.02, h: 18 }], 1, 7, H.ease.inOut(S(0, 1.4)), 2.2);
302
+ ctx.globalAlpha = 1;
303
+ }
304
+ {
305
+ const d = H.ease.inOut(S(1.6, 2.4));
306
+ mono('HOW DOES AI LEARN?', H.lerp(W / 2, 40, d), H.lerp(250, 52, d), H.lerp(56, 24, d), 700, FG, H.lerp(8, 3, d), d > 0.5 ? 'left' : 'center', S(0.1, 0.5));
307
+ mono('one signal, read sixty times', W / 2, 310, 26, 400, 'rgba(242,240,234,0.55)', 1.5, 'center', S(0.6, 1.0) * (1 - d));
308
+ }
309
+
310
+ // ================= DATA =================
311
+ const dataA = S(2.4, 2.8) * (1 - S(6.0, 6.4));
312
+ if (dataA > 0) {
313
+ ctx.globalAlpha = dataA;
314
+ const DX0 = 640, DX1 = 1200, DT = 130, DG = 6.4; // empty stack sits right; counter left
315
+ for (let i = 0; i < N; i++) { ctx.fillStyle = 'rgba(242,240,234,0.24)'; ctx.fillRect(DX0, DT + i * DG, (DX1 - DX0) * H.ease.out(S(2.5 + i * 0.008, 3.0 + i * 0.008)), 1); }
316
+ mono('the model', (DX0 + DX1) / 2, DT - 22, 28, 700, FG, 2, 'center', S(3.0, 3.4));
317
+ mono('(still empty)', (DX0 + DX1) / 2, DT + 200, 24, 400, 'rgba(242,240,234,0.4)', 1, 'center', S(3.0, 3.4));
318
+ // tape
319
+ const ty = 640, speed = 170;
320
+ const pr = H.rng(77);
321
+ const pulses = []; for (let k = 0; k < 14; k++) pulses.push({ x0: k * 100, cat: pr.chance(0.5), h: pr.range(30, 48) });
322
+ const PX = (p) => ((p.x0 - (t - 2.5) * speed) % 1400 + 1400) % 1400 - 60;
323
+ const pts = [];
324
+ for (let x = 0; x <= W; x += 2) {
325
+ let a = nz.n3(x * 0.3, 3, t * 2) * 1.2;
326
+ for (const p of pulses) { const d = (x - PX(p)) / 6; if (Math.abs(d) < 6) a += p.h * Math.exp(-0.5 * d * d); }
327
+ pts.push([x, ty - a]);
328
+ }
329
+ ctx.save(); ctx.beginPath(); ctx.rect(0, 0, W * H.ease.out(S(2.4, 3.0)), H_); ctx.clip();
330
+ ctx.strokeStyle = FG; ctx.lineWidth = 1.8; ctx.beginPath(); pts.forEach(([x, y], i) => (i ? ctx.lineTo(x, y) : ctx.moveTo(x, y))); ctx.stroke();
331
+ for (const p of pulses) { const px = PX(p); if (px < 30 || px > W - 30) continue; mono(p.cat ? 'cat' : 'dog', px, ty + 34, 24, 700, p.cat ? FG : 'rgba(242,240,234,0.55)', 1, 'center'); }
332
+ ctx.restore();
333
+ // hairline arrow: tape → model
334
+ arrow(920, ty - 60, 920, DT + (N - 1) * DG + 14, S(3.3, 3.9));
335
+ mono('examples in', 936, ty - 74, 24, 400, DIM, 1, 'left', S(3.6, 4.0));
336
+ // hero counter
337
+ const n = Math.round(1e6 * H.ease.inOut(S(2.8, 5.8)));
338
+ mono(n.toLocaleString('en-US'), 40, 380, 70, 700, FG, 0, 'left');
339
+ mono('LABELLED EXAMPLES', 44, 420, 22, 400, DIM, 3, 'left');
340
+ ctx.globalAlpha = 1;
341
+ }
342
+
343
+ // ================= LOOP =================
344
+ const LX0 = 260, LX1 = 1060, LY = [250, 410, 570], LK = 2.0;
345
+ const morph = H.ease.inOut(S(10.6, 11.4));
346
+ const loopA = S(6.3, 6.6);
347
+ if (loopA > 0) {
348
+ const ax0 = H.lerp(LX0, SX0, morph), ax1 = H.lerp(LX1, SX1, morph), ay = H.lerp(630, STOP + (N - 1) * gap + 26, morph);
349
+ ctx.globalAlpha = loopA;
350
+ ctx.fillStyle = 'rgba(242,240,234,0.4)'; ctx.fillRect(ax0, ay, ax1 - ax0, 1.5);
351
+ [[U_DOG, 'dog'], [U_CAT, 'cat']].forEach(([u, s]) => { const x = H.lerp(ax0, ax1, u); ctx.fillRect(x - 0.75, ay, 1.5, 9); mono(s, x, ay + 38, H.lerp(30, 26, morph), 700, FG, 2, 'center'); });
352
+ ctx.globalAlpha = 1;
353
+ const rowLabel = ['guess', 'check', 'adjust'];
354
+ const adjMove = H.ease.inOut(S(9.0, 9.9));
355
+ const loopPeaks = [
356
+ [{ u: U_DOG, s: 0.03, h: 46 }, { u: 0.55, s: 0.02, h: 10 }],
357
+ [{ u: U_DOG, s: 0.03, h: 46 }, { u: 0.55, s: 0.02, h: 10 }],
358
+ [{ u: H.lerp(U_DOG, U_CAT, adjMove), s: 0.03, h: 50 }],
359
+ ];
360
+ const starts = [6.6, 8.1, 8.9];
361
+ for (let r = 0; r < 3; r++) {
362
+ const sw = H.ease.inOut(S(starts[r], starts[r] + 0.6)); if (sw <= 0) continue;
363
+ const xa = H.lerp(LX0, SX0, morph), xb = H.lerp(LX1, SX1, morph), y = H.lerp(LY[r], STOP + r * gap, morph), k = H.lerp(LK, SK, morph);
364
+ trace(xa, xb, y, k, loopPeaks[r], 0.5, r, sw, H.lerp(2.2, 1.4, morph));
365
+ mono(rowLabel[r], xa - 24, y + 8, 30, 700, r === (t < 8.1 ? 0 : t < 8.9 ? 1 : 2) ? FG : 'rgba(242,240,234,0.4)', 2, 'right', 1 - morph);
366
+ }
367
+ const fade = 1 - morph;
368
+ if (fade > 0) {
369
+ const X = (u) => H.lerp(LX0, LX1, u);
370
+ const g = S(7.1, 7.4) * fade * (1 - S(8.0, 8.2) * 0.5);
371
+ if (g > 0) {
372
+ const w = mono('“dog?”', X(U_DOG), LY[0] - 120, 34, 700, FG, 2, 'center', g);
373
+ ctx.globalAlpha = g; ctx.strokeStyle = FG; ctx.lineWidth = 3; const xx = X(U_DOG) + w / 2 + 14, xy = LY[0] - 146;
374
+ ctx.beginPath(); ctx.moveTo(xx, xy); ctx.lineTo(xx + 22, xy + 22); ctx.moveTo(xx + 22, xy); ctx.lineTo(xx, xy + 22); ctx.stroke();
375
+ const rp = S(7.4, 7.9); ctx.lineWidth = 2; ctx.beginPath();
376
+ for (let q = 0; q <= 60 * rp; q++) { const a = -1.9 + q / 60 * 6.8, rr = 1 + q * 0.0015; const px = X(U_DOG) + Math.cos(a) * 54 * rr, py = LY[0] - 52 + Math.sin(a) * 66 * rr; q ? ctx.lineTo(px, py) : ctx.moveTo(px, py); }
377
+ ctx.stroke(); ctx.globalAlpha = 1;
378
+ }
379
+ const c = S(8.3, 8.7) * fade;
380
+ if (c > 0) {
381
+ ctx.globalAlpha = c; ctx.setLineDash([6, 6]); ctx.strokeStyle = FG; ctx.lineWidth = 2; ctx.beginPath();
382
+ for (let q = 0; q <= 80; q++) { const u = U_CAT - 0.09 + q / 80 * 0.18, d = (u - U_CAT) / 0.03; const y = LY[1] - 50 * LK * Math.exp(-0.5 * d * d); q ? ctx.lineTo(X(u), y) : ctx.moveTo(X(u), y); }
383
+ ctx.stroke(); ctx.setLineDash([]); ctx.globalAlpha = 1;
384
+ mono('answer: cat', X(U_CAT) + 70, LY[1] - 80, 28, 700, FG, 1.5, 'left', c);
385
+ const e = S(8.6, 9.0) * fade;
386
+ if (e > 0) { const y = LY[1] - 46; arrow(X(U_DOG) + 34, y, X(U_CAT) - 34, y, e, FG, 2.4); mono('error', (X(U_DOG) + X(U_CAT)) / 2, y - 14, 26, 700, 'rgba(242,240,234,0.85)', 2, 'center', e); }
387
+ }
388
+ const ad = S(9.0, 9.3) * fade * (1 - S(9.9, 10.1));
389
+ if (ad > 0) mono('shift the weights →', X(0.5), LY[2] + 40, 26, 400, 'rgba(242,240,234,0.85)', 1.5, 'center', ad);
390
+ const ok = S(9.9, 10.2) * fade;
391
+ if (ok > 0) {
392
+ const w = mono('“cat”', X(U_CAT) + 64, LY[2] - 50, 34, 700, FG, 2, 'left', ok);
393
+ ctx.globalAlpha = ok; ctx.strokeStyle = FG; ctx.lineWidth = 3; ctx.lineJoin = 'round'; const xx = X(U_CAT) + 64 + w + 14, xy = LY[2] - 72;
394
+ ctx.beginPath(); ctx.moveTo(xx, xy + 10); ctx.lineTo(xx + 8, xy + 20); ctx.lineTo(xx + 26, xy - 4); ctx.stroke(); ctx.globalAlpha = 1;
395
+ }
396
+ const la = S(10.0, 10.4) * fade;
397
+ if (la > 0) {
398
+ ctx.globalAlpha = la; ctx.strokeStyle = 'rgba(242,240,234,0.7)'; ctx.lineWidth = 2;
399
+ const lx = LX0 - 150;
400
+ ctx.beginPath(); ctx.moveTo(lx + 20, LY[2]); ctx.lineTo(lx, LY[2]); ctx.lineTo(lx, LY[0]); ctx.lineTo(lx + 16, LY[0]); ctx.stroke();
401
+ ctx.beginPath(); ctx.moveTo(lx + 8, LY[0] - 7); ctx.lineTo(lx + 16, LY[0]); ctx.lineTo(lx + 8, LY[0] + 7); ctx.stroke();
402
+ ctx.save(); ctx.translate(lx - 14, (LY[0] + LY[2]) / 2); ctx.rotate(-Math.PI / 2); mono('repeat', 0, 0, 24, 700, 'rgba(242,240,234,0.75)', 3, 'center'); ctx.restore(); ctx.globalAlpha = 1;
403
+ }
404
+ }
405
+ }
406
+
407
+ // ================= PROGRESS =================
408
+ if (t >= 11.2) {
409
+ for (let i = 3; i < N; i++) {
410
+ const sw = H.clamp((t - (11.3 + (i - 3) * 0.026)) / 0.22);
411
+ if (sw <= 0) break;
412
+ trace(SX0, SX1, STOP + i * gap, SK, rowPeaks(i), H.lerp(1, 0.25, i / N), i, sw, i === N - 1 && t > 13.0 ? 2.6 : 1.4);
413
+ }
414
+ // the answer axis, redrawn over the occluding fills of the last rounds
415
+ { const ay = STOP + (N - 1) * gap + 26; ctx.fillStyle = BGC; ctx.fillRect(SX0 - 10, ay - 2, SX1 - SX0 + 20, 48); ctx.fillStyle = 'rgba(242,240,234,0.4)'; ctx.fillRect(SX0, ay, SX1 - SX0, 1.5);
416
+ [[U_DOG, 'dog'], [U_CAT, 'cat']].forEach(([u, s]) => { const x = H.lerp(SX0, SX1, u); ctx.fillRect(x - 0.75, ay, 1.5, 9); mono(s, x, ay + 38, 26, 700, FG, 2, 'center', 1 - 0.5 * S(13.3, 13.8)); }); }
417
+ mono('round 1', SX0 - 16, STOP + 8, 24, 400, 'rgba(242,240,234,0.72)', 1, 'right', S(11.4, 11.7));
418
+ mono('round 60', SX0 - 16, STOP + (N - 1) * gap + 8, 24, 400, 'rgba(242,240,234,0.72)', 1, 'right', S(12.7, 13.0));
419
+ const p = H.ease.inOut(S(11.3, 12.8));
420
+ mono('ACCURACY', SX1 + 34, 300, 22, 400, DIM, 3, 'left');
421
+ mono(Math.round(61 + 36 * p) + '%', SX1 + 30, 376, 84, 700, FG, 0, 'left');
422
+ const e = S(12.9, 13.4);
423
+ if (e > 0) {
424
+ ctx.fillStyle = FG; ctx.fillRect(SX1 + 34, 394, 170 * e, 3);
425
+ ctx.globalAlpha = e; ctx.strokeStyle = FG; ctx.lineWidth = 2;
426
+ const y = STOP + (N - 1) * gap; ctx.beginPath(); ctx.moveTo(SX1 + 12, y - 90); ctx.lineTo(SX1 + 20, y - 90); ctx.lineTo(SX1 + 20, y + 2); ctx.lineTo(SX1 + 12, y + 2); ctx.stroke();
427
+ mono('one clean', SX1 + 34, y - 52, 24, 700, FG, 1, 'left'); mono('peak: cat', SX1 + 34, y - 22, 24, 700, FG, 1, 'left'); ctx.globalAlpha = 1;
428
+ }
429
+ }
430
+ // ================= TAKEAWAY =================
431
+ mono('MORE EXAMPLES → BETTER GUESSES', W / 2, 694, 44, 700, FG, 1, 'center', S(13.3, 13.8));
432
+
433
+ printFinish(ctx, 0.06, 8 + Math.floor(t * 12));
434
+ },
435
+ });
436
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "id": 77,
3
+ "name": "Ridgeline",
4
+ "nameZh": "山脊线图",
5
+ "family": "Data & Information",
6
+ "familyZh": "数据与信息",
7
+ "description": "Sixty stacked traces of noisy signal, each filled black so it occludes the one behind, drawn as thin white lines in a perfectly centred block with a tiny typographic caption.",
8
+ "motionNotes": "Motion: Traces are plotted one after another from the top, each swept left to right like a pen recorder and occluding the ones behind; once the stack is complete the peaks ripple like a live signal and the caption types in.",
9
+ "explainerNotes": "Explainer: Each white trace is one training round: a recorder tape feeds labelled pulses into the empty stack, three magnified traces act out guess / check / adjust (the peak lands on \"dog\", a dashed target shows \"cat\", the peak slides over), then the camera pulls back and sixty rounds plot themselves as the noisy peaks align into one clean ridge, captioned in Space Mono.",
10
+ "code": "code.js",
11
+ "registeredAs": "ridgeline",
12
+ "source": "https://www.futurepedia.io/resources/ai-style-atlas/view"
13
+ }