@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": 73,
3
+ "name": "Patent Drawing",
4
+ "nameZh": "专利图纸",
5
+ "family": "Illustration",
6
+ "familyZh": "插画",
7
+ "description": "A 1930s US patent sheet: ruling-pen black ink line art with shade lines, parallel-line and stipple shading, section hatching, reference numerals on curved leaders, typeset header and inked signatures on yellowed paper.",
8
+ "motionNotes": "Motion: Lines are inked one stroke at a time like a draughtsman at work — outlines first, then hatching, then numerals — while the FIG. 3 gear train slowly turns.",
9
+ "explainerNotes": "Explainer: The camera travels along one long patent sheet as FIG. 4–6 are inked stroke by stroke: ruled arrows and leader lines tie labels to parts, odometer drums count the examples and the accuracy, and an examiner's red pencil rings the wrong guess and the 97%.",
10
+ "code": "code.js",
11
+ "registeredAs": "patent-drawing",
12
+ "source": "https://www.futurepedia.io/resources/ai-style-atlas/view"
13
+ }
@@ -0,0 +1,595 @@
1
+ {
2
+ // ---------- print helpers (local) ----------
3
+ const fieldNoise = (w, h, seed, cell, oct, sx = 1, sy = 1) => {
4
+ const nz = H.makeNoise(seed), gw = Math.ceil(w / cell) + 2, gh = Math.ceil(h / cell) + 2, g = new Float32Array(gw * gh);
5
+ for (let j = 0; j < gh; j++) for (let i = 0; i < gw; i++) g[j * gw + i] = nz.fbm2(i * 0.35 * sx, j * 0.35 * sy, oct);
6
+ const out = new Float32Array(w * h);
7
+ for (let y = 0; y < h; y++) {
8
+ const fy = y / cell, j = fy | 0, ty = fy - j;
9
+ for (let x = 0; x < w; x++) {
10
+ const fx = x / cell, i = fx | 0, tx = fx - i, k = j * gw + i;
11
+ const a = g[k] + (g[k + 1] - g[k]) * tx, b = g[k + gw] + (g[k + gw + 1] - g[k + gw]) * tx;
12
+ out[y * w + x] = a + (b - a) * ty;
13
+ }
14
+ }
15
+ return out;
16
+ };
17
+ // deterministic noise fields are cached across frames (pure: same inputs -> same arrays)
18
+ const CACHE = {};
19
+ const cachedField = (key, ...a) => CACHE[key] || (CACHE[key] = fieldNoise(...a));
20
+
21
+ // mottled ink coverage: modulates alpha of a layer
22
+ const inkify = (layer, seed, mottle, speck) => {
23
+ const c = layer.getContext('2d'), w = layer.width, h = layer.height, img = c.getImageData(0, 0, w, h), d = img.data;
24
+ const n1 = cachedField('ink1' + seed, w, h, seed, 5, 3), n2 = cachedField('ink2' + seed, w, h, seed + 9, 40, 3), r = H.rng(seed + 3);
25
+ for (let i = 0, p = 0; i < d.length; i += 4, p++) {
26
+ if (!d[i + 3]) { r(); continue; }
27
+ let a = 1 - mottle * Math.max(0, n1[p] * 1.6 + n2[p] * 0.9);
28
+ if (r() < speck * (0.4 + Math.max(0, n2[p]) * 3)) a *= 0.25;
29
+ d[i + 3] *= H.clamp(a, 0, 1);
30
+ }
31
+ c.putImageData(img, 0, 0);
32
+ };
33
+
34
+ const C = { cream: '#ece2c9', red: '#cf3a2a', yellow: '#efb526', blue: '#1f4f9b', black: '#1c1a18' };
35
+
36
+ // ring helper
37
+ const ring = (c, x, y, ro, ri) => { c.beginPath(); c.arc(x, y, ro, 0, Math.PI * 2); c.arc(x, y, ri, 0, Math.PI * 2, true); c.fill(); };
38
+
39
+ // constructed geometric lettering (Bayer-like universal alphabet)
40
+ const letter = (c, ch, x, base, xh, sw) => {
41
+ const R = xh / 2;
42
+ if (ch === 'o') { ring(c, x + R, base - R, R, R - sw); return xh; }
43
+ if (ch === 'b') { c.fillRect(x, base - xh * 1.55, sw, xh * 1.55); ring(c, x + R, base - R, R, R - sw); return xh; }
44
+ if (ch === 'r') {
45
+ c.fillRect(x, base - xh, sw, xh);
46
+ c.beginPath(); c.arc(x + R, base - R, R, Math.PI, Math.PI * 1.62); c.arc(x + R, base - R, R - sw, Math.PI * 1.62, Math.PI, true); c.fill();
47
+ return xh * 0.66;
48
+ }
49
+ if (ch === 't') {
50
+ c.fillRect(x + xh * 0.18, base - xh * 1.4, sw, xh * 1.4);
51
+ c.fillRect(x, base - xh, xh * 0.62, sw * 0.9);
52
+ return xh * 0.62;
53
+ }
54
+ return xh * 0.5;
55
+ };
56
+
57
+ // ===================== EXPLAINER: "How does AI learn?" =====================
58
+ // One long printed sheet of four panels; the camera tracks along it (Bayer-style info-design spread),
59
+ // then pulls back to show the whole sheet as one diagram for the takeaway.
60
+ let EX_PAPER = null;
61
+ const exPaper = (W, HH) => {
62
+ if (EX_PAPER) return EX_PAPER;
63
+ const cv = H.layer(W, HH), x = cv.getContext('2d'), img = x.createImageData(W, HH), pd = img.data;
64
+ const lo = cachedField('lo', W, HH, 11, 24, 4), fib = cachedField('fib', W, HH, 12, 2, 2, 3.5, 0.5), r0 = H.rng(5);
65
+ const base = H.hex(C.cream), tan = H.hex('#c9ab78');
66
+ for (let y = 0, p = 0; y < HH; y++) for (let xx = 0; xx < W; xx++, p++) {
67
+ const ex = Math.min(xx, W - xx) / W, ey = Math.min(y, HH - y) / HH;
68
+ const edge = Math.pow(1 - H.clamp(Math.min(ex * 3.2, ey * 2.2) + lo[p] * 0.15, 0, 1), 3);
69
+ const k = 0.35 * edge + 0.12 * Math.max(0, lo[p]);
70
+ const s = 1 + fib[p] * 0.035 + (r0() - 0.5) * 0.04, i = p * 4;
71
+ pd[i] = (base[0] + (tan[0] - base[0]) * k) * s; pd[i + 1] = (base[1] + (tan[1] - base[1]) * k) * s; pd[i + 2] = (base[2] + (tan[2] - base[2]) * k) * s; pd[i + 3] = 255;
72
+ }
73
+ x.putImageData(img, 0, 0);
74
+ const rf = H.rng(77);
75
+ for (let i = 0; i < 26; i++) {
76
+ const px = rf.range(0, W), py = rf.range(0, HH), rr = rf.range(2, 10), g = x.createRadialGradient(px, py, 0, px, py, rr);
77
+ g.addColorStop(0, 'rgba(140,90,40,0.22)'); g.addColorStop(1, 'rgba(140,90,40,0)'); x.fillStyle = g; x.beginPath(); x.arc(px, py, rr, 0, 7); x.fill();
78
+ }
79
+ return (EX_PAPER = cv);
80
+ };
81
+
82
+ // geometric pictures: cat = yellow card, dog = blue card
83
+ const exCard = (c, kind, x, y, s) => {
84
+ c.save(); c.translate(x, y);
85
+ c.fillStyle = kind === 'cat' ? C.yellow : C.blue; c.fillRect(-s / 2, -s / 2, s, s);
86
+ if (kind === 'cat') {
87
+ c.fillStyle = C.black;
88
+ c.beginPath(); c.moveTo(-s * 0.3, -s * 0.06); c.lineTo(-s * 0.26, -s * 0.38); c.lineTo(-s * 0.06, -s * 0.2); c.closePath(); c.fill();
89
+ c.beginPath(); c.moveTo(s * 0.3, -s * 0.06); c.lineTo(s * 0.26, -s * 0.38); c.lineTo(s * 0.06, -s * 0.2); c.closePath(); c.fill();
90
+ c.beginPath(); c.arc(0, s * 0.06, s * 0.28, 0, 7); c.fill();
91
+ c.fillStyle = C.yellow; c.beginPath(); c.arc(-s * 0.1, s * 0.02, s * 0.05, 0, 7); c.arc(s * 0.1, s * 0.02, s * 0.05, 0, 7); c.fill();
92
+ c.fillStyle = C.red; c.beginPath(); c.moveTo(-s * 0.05, s * 0.12); c.lineTo(s * 0.05, s * 0.12); c.lineTo(0, s * 0.18); c.closePath(); c.fill();
93
+ } else {
94
+ c.fillStyle = C.cream; c.beginPath(); c.arc(0, s * 0.04, s * 0.27, 0, 7); c.fill();
95
+ c.fillStyle = C.black;
96
+ c.beginPath(); c.arc(-s * 0.27, s * 0.0, s * 0.13, -Math.PI / 2, Math.PI / 2, true); c.closePath(); c.fill();
97
+ c.beginPath(); c.arc(s * 0.27, s * 0.0, s * 0.13, -Math.PI / 2, Math.PI / 2); c.closePath(); c.fill();
98
+ c.beginPath(); c.arc(-s * 0.09, -s * 0.01, s * 0.04, 0, 7); c.arc(s * 0.09, -s * 0.01, s * 0.04, 0, 7); c.fill();
99
+ c.beginPath(); c.arc(0, s * 0.12, s * 0.06, 0, 7); c.fill();
100
+ }
101
+ c.restore();
102
+ };
103
+ // label tag that lands on the thing it labels
104
+ const exTag = (c, txt, x, y, p, size = 28, bg = C.black, fg = C.cream) => {
105
+ if (p <= 0) return;
106
+ c.save(); c.font = `700 ${size}px "Space Grotesk"`; c.textBaseline = 'middle';
107
+ const w = c.measureText(txt).width + size * 0.9, h = size * 1.5, dy = -(1 - H.ease.back(p)) * 30;
108
+ c.fillStyle = bg; c.fillRect(x - w / 2, y - h / 2 + dy, w, h);
109
+ c.fillStyle = fg; c.textAlign = 'center'; c.fillText(txt, x, y + dy + 1);
110
+ c.restore();
111
+ };
112
+ // thick Bauhaus arrow (bar + triangle), drawn on with progress p
113
+ const exArrow = (c, x0, y0, x1, y1, p, w = 10, col = C.black) => {
114
+ if (p <= 0) return;
115
+ const L = Math.hypot(x1 - x0, y1 - y0), a = Math.atan2(y1 - y0, x1 - x0), l = L * p;
116
+ c.save(); c.translate(x0, y0); c.rotate(a); c.fillStyle = col;
117
+ c.fillRect(0, -w / 2, Math.max(0, l - w * 2), w);
118
+ c.beginPath(); c.moveTo(l, 0); c.lineTo(l - w * 2.6, -w * 1.5); c.lineTo(l - w * 2.6, w * 1.5); c.closePath(); c.fill();
119
+ c.restore();
120
+ };
121
+ // the model: the robot head from the poster, with three weight dials on a control bar
122
+ const exRobot = (c, x, y, s, dials, look, mood = 0) => {
123
+ const k = s / 300, hx = x - s / 2, hy = y - s / 2;
124
+ c.fillStyle = C.black; c.fillRect(x - 100 * k, hy - 62 * k, 200 * k, 52 * k);
125
+ dials.forEach((a, i) => {
126
+ const dx = x + (i - 1) * 62 * k, dy = hy - 36 * k;
127
+ c.fillStyle = C.cream; c.beginPath(); c.arc(dx, dy, 19 * k, 0, 7); c.fill();
128
+ c.save(); c.translate(dx, dy); c.rotate(a); c.fillStyle = [C.red, C.blue, C.black][i]; c.fillRect(-3 * k, -17 * k, 6 * k, 17 * k); c.restore();
129
+ });
130
+ c.fillStyle = C.red; c.beginPath(); c.arc(hx, y, 50 * k, Math.PI / 2, Math.PI * 1.5); c.closePath(); c.fill();
131
+ c.fillStyle = C.black; c.beginPath(); c.arc(hx + s, y, 50 * k, -Math.PI / 2, Math.PI / 2); c.closePath(); c.fill();
132
+ c.fillStyle = C.blue; c.fillRect(hx, hy, s, s);
133
+ c.fillStyle = C.yellow; c.beginPath(); c.arc(hx + 85 * k, hy + 105 * k, 50 * k, 0, 7); c.fill();
134
+ c.fillStyle = mood > 0 ? C.yellow : C.red; c.fillRect(hx + s - 135 * k, hy + 55 * k, 100 * k, 100 * k);
135
+ const dx = H.lerp(-8, 18, look) * k;
136
+ c.fillStyle = C.black; c.beginPath(); c.arc(hx + 85 * k + dx, hy + 105 * k, 21 * k, 0, 7); c.arc(hx + s - 85 * k + dx, hy + 105 * k, 21 * k, 0, 7); c.fill();
137
+ c.fillStyle = C.yellow; c.beginPath(); c.moveTo(x - 26 * k, hy + 150 * k); c.lineTo(x + 26 * k, hy + 150 * k); c.lineTo(x, hy + 196 * k); c.closePath(); c.fill();
138
+ c.fillStyle = C.black; c.fillRect(x - 92 * k, hy + 220 * k, 184 * k, 46 * k);
139
+ c.fillStyle = C.blue; for (let i = 0; i < 5; i++) c.fillRect(x - 76 * k + i * 33 * k, hy + 228 * k, 13 * k, 30 * k);
140
+ };
141
+ const fmt = (n) => Math.round(n).toLocaleString('en-US');
142
+
143
+ // colour separations: every fill lands on its own plate (yellow / red / blue / black) and knocks the same shape out
144
+ // of the other plates, exactly like a litho knockout. Cream fills knock out all plates (reversed type shows paper).
145
+ // The plates are then printed with the per-colour misregistration offsets, overlapping slivers multiply.
146
+ const PLATE_COLS = ['yellow', 'red', 'blue', 'black'];
147
+ const PLATE_OF = { [C.yellow]: 0, [C.red]: 1, [C.blue]: 2, [C.black]: 3 };
148
+ let PLATES = null;
149
+ const plateCtx = (W, HH) => {
150
+ if (!PLATES || PLATES[0].width !== W || PLATES[0].height !== HH) PLATES = PLATE_COLS.map(() => H.layer(W, HH));
151
+ const cs = PLATES.map((pl) => { const x = pl.getContext('2d'); x.setTransform(1, 0, 0, 1, 0, 0); x.globalAlpha = 1; x.globalCompositeOperation = 'source-over'; x.clearRect(0, 0, W, HH); return x; });
152
+ let fill = C.black, stroke = C.black;
153
+ const paint = (style, op) => { const k = style in PLATE_OF ? PLATE_OF[style] : style === C.cream ? -1 : 3;
154
+ cs.forEach((x, i) => { if (i === k) op(x); else { x.globalCompositeOperation = 'destination-out'; op(x); x.globalCompositeOperation = 'source-over'; } }); };
155
+ const DRAW = { fill: 1, fillRect: 1, fillText: 1, stroke: 2, strokeRect: 2, strokeText: 2 };
156
+ return new Proxy({}, {
157
+ get(_, prop) {
158
+ if (prop === 'fillStyle') return fill; if (prop === 'strokeStyle') return stroke;
159
+ const v = cs[0][prop];
160
+ if (typeof v !== 'function') return v;
161
+ if (DRAW[prop]) return (...a) => paint(DRAW[prop] === 1 ? fill : stroke, (x) => x[prop](...a));
162
+ if (prop === 'measureText' || prop.startsWith('create') || prop.startsWith('get') || prop.startsWith('isPoint')) return (...a) => cs[0][prop](...a);
163
+ return (...a) => { let r; cs.forEach((x) => { r = x[prop](...a); }); return r; };
164
+ },
165
+ set(_, prop, v) { if (prop === 'fillStyle') fill = v; else if (prop === 'strokeStyle') stroke = v; cs.forEach((x) => { x[prop] = v; }); return true; },
166
+ });
167
+ };
168
+
169
+ const explainBauhaus = (ctx, W, HH, t) => {
170
+ const E = H.ease, cl = H.clamp;
171
+ const S = (a, b) => cl((t - a) / (b - a), 0, 1); // segment progress
172
+ const PW = 1280;
173
+ // ---------- camera along the sheet ----------
174
+ const keys = [[0, 0], [2.0, 0], [2.9, 1], [5.8, 1], [6.6, 2], [10.3, 2], [11.0, 3]];
175
+ let pan = 0; for (let i = 0; i < keys.length - 1; i++) { const [ta, a] = keys[i], [tb, b] = keys[i + 1]; if (t >= ta) pan = t >= tb ? b : H.lerp(a, b, E.inOut((t - ta) / (tb - ta))); }
176
+ const z = E.inOut(S(12.9, 13.7)), sc = H.lerp(1, 0.25, z), camX = pan * PW - (960 * z) / sc * (pan === 3 ? 1 : 0), oy = 150 * z;
177
+
178
+ ctx.drawImage(exPaper(W, HH), 0, 0);
179
+ const c = plateCtx(W, HH);
180
+ const reg = { yellow: [2, -1], red: [-1.5, 1], blue: [1, 2], black: [0, 0] };
181
+
182
+ c.save(); c.translate(0, oy); c.scale(sc, sc); c.translate(-camX, 0);
183
+ const vis = (k) => (k + 1) * PW > camX && k * PW < camX + W / sc;
184
+
185
+ // continuous base rule running the whole length of the sheet (ties the panels together)
186
+ c.fillStyle = C.black; c.fillRect(56, HH - 70, 4 * PW - 112, 14);
187
+
188
+ // ---------- panel 0: hook ----------
189
+ if (vis(0)) {
190
+ c.save();
191
+ c.fillStyle = C.black; c.fillRect(56, 56, 14, (HH - 126) * E.out(S(0, 0.6)));
192
+ const qs = E.back(S(0.25, 0.85));
193
+ c.fillStyle = C.red; c.beginPath(); c.arc(980, 330, 190 * qs, 0, 7); c.fill();
194
+ if (qs > 0) { // constructed question mark
195
+ c.save(); c.translate(980, 330); c.scale(qs, qs); c.fillStyle = C.cream;
196
+ c.beginPath(); c.arc(0, -55, 62, Math.PI, Math.PI * 2.5); c.arc(0, -55, 30, Math.PI * 2.5, Math.PI, true); c.closePath(); c.fill();
197
+ c.fillRect(-16, -2, 32, 50); c.fillRect(-16, 66, 32, 32); c.restore();
198
+ }
199
+ c.fillStyle = C.yellow; c.fillRect(1100, 470, 120 * E.out(S(0.6, 1.0)), 40);
200
+ c.fillStyle = C.blue; c.beginPath(); c.moveTo(800, 560); c.lineTo(800 + 90 * E.out(S(0.7, 1.1)), 560); c.lineTo(800, 470); c.closePath(); c.fill();
201
+ c.restore();
202
+ }
203
+ // ---------- panel 1: data ----------
204
+ if (vis(1)) {
205
+ c.save(); c.translate(PW, 0);
206
+ // conveyor rule + model head
207
+ c.fillStyle = C.black; c.fillRect(60, 470, 800 * E.out(S(2.5, 3.2)), 12);
208
+ const look = 0.5 + 0.5 * Math.sin(t * 2);
209
+ exRobot(c, 1030, 330, 250, [0.3, -0.6, 1.1], look);
210
+ exArrow(c, 760, 400, 880, 360, E.out(S(2.9, 3.3)), 9);
211
+ // stream of labelled examples riding the conveyor into the model's mouth
212
+ const tl = t - 2.6;
213
+ for (let i = 0; i < 14; i++) {
214
+ const x = 40 + (tl - i * 0.52) * 300; if (x < -60 || tl - i * 0.52 < 0) continue;
215
+ const kind = H.rng(i * 7 + 1)() < 0.5 ? 'cat' : 'dog';
216
+ const into = cl((x - 760) / 140, 0, 1), s = 112 * (1 - into * 0.75);
217
+ if (into >= 1) continue;
218
+ const cx = Math.min(x, 760) + into * 160, cy = 395 - into * 50;
219
+ exCard(c, kind, cx, cy, s);
220
+ exTag(c, kind, cx, cy + s / 2 + 4, cl((tl - i * 0.52) / 0.3, 0, 1) * (1 - into), 28 * (1 - into * 0.6));
221
+ }
222
+ // label for the stack
223
+ exTag(c, 'training data', 330, 575, S(3.3, 3.6), 28, C.red, C.cream);
224
+ // counter block (stamped numerals)
225
+ const ct = S(2.9, 5.6), n = ct < 1 ? Math.pow(ct, 3) * 1e6 : 1e6;
226
+ c.fillStyle = C.red; c.fillRect(110, 160, 420 * E.out(S(2.8, 3.1)), 120);
227
+ if (S(2.8, 3.1) >= 1) {
228
+ c.fillStyle = C.cream; c.font = '700 72px "Space Grotesk"'; c.textBaseline = 'alphabetic'; c.fillText(fmt(n), 130, 250);
229
+ c.fillStyle = C.black; c.font = '700 34px "Space Grotesk"'; c.fillText('examples', 545, 250);
230
+ }
231
+ c.restore();
232
+ }
233
+ // ---------- panel 2: guess -> check -> adjust ----------
234
+ if (vis(2)) {
235
+ c.save(); c.translate(2 * PW, 0);
236
+ const adj = E.inOut(S(8.4, 9.2));
237
+ const dials = [H.lerp(0.3, -0.9, adj), H.lerp(-0.6, 0.8, adj), H.lerp(1.1, 0.2, adj)];
238
+ const right = t > 9.5;
239
+ exRobot(c, 300, 360, 250, dials, right ? 1 : 0.9, right ? 1 : 0);
240
+ // new picture arrives
241
+ const ix = H.lerp(760, 560, E.out(S(6.4, 6.9)));
242
+ exCard(c, 'cat', ix, 330, 110);
243
+ exArrow(c, ix - 70, 330, 450, 330, E.out(S(6.7, 7.0)), 8);
244
+ // guess #1: "dog?" -> red X (check) + circled
245
+ if (t < 9.3) {
246
+ exTag(c, 'dog?', 545, 190, S(6.95, 7.2), 30);
247
+ const xp = E.out(S(7.55, 7.75));
248
+ if (xp > 0) { c.save(); c.translate(648, 190); c.rotate(Math.PI / 4); c.fillStyle = C.red; c.fillRect(-34 * xp, -7, 68 * xp, 14); c.fillRect(-7, -34 * xp, 14, 68 * xp); c.restore(); }
249
+ const rp = S(7.6, 8.0); // emphasis ring drawn round the wrong guess
250
+ if (rp > 0) { c.strokeStyle = C.red; c.lineWidth = 7; c.beginPath(); c.ellipse(585, 190, 120, 62, 0, -Math.PI / 2, -Math.PI / 2 + Math.PI * 2 * rp); c.stroke(); }
251
+ } else {
252
+ exTag(c, 'cat', 545, 190, S(9.35, 9.6), 30, C.black, C.cream);
253
+ const cp = E.out(S(9.6, 9.85));
254
+ if (cp > 0) { c.save(); c.translate(618, 205); c.rotate(-Math.PI / 4); c.fillStyle = C.black; c.fillRect(-8, -36 * cp, 16, 36 * cp); c.fillRect(-8, -8, 64 * cp, 16); c.restore(); }
255
+ }
256
+ // the loop diagram: guess (circle) -> check (square) -> adjust (triangle)
257
+ const G = [960, 170], K = [1150, 470], A = [770, 470];
258
+ const node = (i, d) => E.back(S(d, d + 0.35));
259
+ const active = t < 7.4 ? 0 : t < 8.2 ? 1 : t < 9.3 ? 2 : Math.floor((t - 9.3) * 3) % 3;
260
+ const pulse = (i) => (i === active && t > 7.0 ? 1 + 0.08 * Math.sin(t * 10) : 1);
261
+ let s = node(0, 6.9) * pulse(0); c.fillStyle = C.yellow; c.beginPath(); c.arc(G[0], G[1], 62 * s, 0, 7); c.fill();
262
+ s = node(1, 7.4) * pulse(1); c.fillStyle = C.red; c.fillRect(K[0] - 58 * s, K[1] - 58 * s, 116 * s, 116 * s);
263
+ s = node(2, 8.1) * pulse(2); c.fillStyle = C.blue; c.beginPath(); c.moveTo(A[0], A[1] - 70 * s); c.lineTo(A[0] + 66 * s, A[1] + 52 * s); c.lineTo(A[0] - 66 * s, A[1] + 52 * s); c.closePath(); c.fill();
264
+ exTag(c, 'guess', G[0], G[1] + 2, S(7.0, 7.3), 28);
265
+ exTag(c, 'check', K[0], K[1] + 2, S(7.5, 7.8), 28);
266
+ exTag(c, 'adjust', A[0], A[1] + 16, S(8.2, 8.5), 28);
267
+ exArrow(c, G[0] + 50, G[1] + 50, K[0] - 30, K[1] - 75, E.out(S(7.2, 7.5)), 9);
268
+ exArrow(c, K[0] - 75, K[1] + 10, A[0] + 80, A[1] + 10, E.out(S(7.9, 8.2)), 9);
269
+ exArrow(c, A[0] + 5, A[1] - 85, G[0] - 55, G[1] + 45, E.out(S(9.0, 9.3)), 9);
270
+ // error signal: red square travels from check back to the model's dials
271
+ const ep = S(8.0, 8.6);
272
+ if (ep > 0 && ep < 1) { const ex = H.lerp(K[0] - 60, 300, E.inOut(ep)), ey = H.lerp(K[1] - 40, 190, E.inOut(ep)) - Math.sin(ep * Math.PI) * 120; c.fillStyle = C.red; c.fillRect(ex - 16, ey - 16, 32, 32); }
273
+ if (ep >= 1 && t < 9.3) exTag(c, 'error', 300, 150, 1, 28, C.red, C.cream);
274
+ // loop token keeps circling after it gets it right (the loop repeats)
275
+ if (t > 9.4) { const u = ((t - 9.4) * 1.4) % 1, seg = Math.floor(u * 3), f = u * 3 - seg, P3 = [G, K, A], a = P3[seg], b = P3[(seg + 1) % 3]; c.fillStyle = C.black; c.beginPath(); c.arc(H.lerp(a[0], b[0], f), H.lerp(a[1], b[1], f), 12, 0, 7); c.fill(); }
276
+ c.restore();
277
+ }
278
+ // ---------- panel 3: progress ----------
279
+ if (vis(3)) {
280
+ c.save(); c.translate(3 * PW, 0);
281
+ const gx = 120, gy = 600, gw = 700, gh = 420;
282
+ c.fillStyle = C.black; c.fillRect(gx, gy - gh, 10, gh); c.fillRect(gx, gy, gw, 10);
283
+ const n = 10, prog = S(10.9, 12.3);
284
+ for (let i = 0; i < n; i++) {
285
+ const acc = 61 + 36 * (1 - Math.pow(1 - i / (n - 1), 2)), bp = E.out(cl(prog * n - i, 0, 1));
286
+ const h = (acc - 40) / 60 * gh * bp;
287
+ c.fillStyle = [C.red, C.yellow, C.blue][i % 3];
288
+ if (i === n - 1 && t > 12.3) c.fillStyle = Math.floor(t * 6) % 2 ? C.red : C.black;
289
+ c.fillRect(gx + 30 + i * 66, gy - h, 50, h);
290
+ }
291
+ exTag(c, 'training rounds →', gx + gw / 2, gy + 48, S(10.9, 11.2), 28);
292
+ c.save(); c.translate(gx - 34, gy - gh / 2); c.rotate(-Math.PI / 2); exTag(c, 'accuracy', 0, 0, S(11.0, 11.3), 28); c.restore();
293
+ // the counting number
294
+ const acc = Math.round(H.lerp(61, 97, E.inOut(prog)));
295
+ c.fillStyle = C.black; c.font = '700 150px "Space Grotesk"'; c.textBaseline = 'alphabetic';
296
+ if (t > 10.8) c.fillText(acc + '%', 860, 330);
297
+ c.font = '700 30px "Space Grotesk"'; if (t > 10.8) c.fillText('accuracy', 870, 380);
298
+ c.font = '700 34px "Space Grotesk"'; if (t > 11.2) c.fillText('61% → 97%', 870, 430);
299
+ const rp = S(12.3, 12.7); // emphasis: red ring drawn round 97%
300
+ if (rp > 0) { c.strokeStyle = C.red; c.lineWidth = 9; c.beginPath(); c.ellipse(1005, 268, 185, 84, -0.06, -Math.PI * 0.6, -Math.PI * 0.6 + Math.PI * 2 * rp); c.stroke(); }
301
+ c.restore();
302
+ }
303
+ c.restore();
304
+
305
+ // ---------- pinned header (screen space): the hook shrinks into it ----------
306
+ const hp = E.inOut(S(1.6, 2.4));
307
+ const tx = H.lerp(120, 96, hp), ty = H.lerp(350, 64, hp), ts = H.lerp(1, 0.46, hp);
308
+ c.save(); c.translate(tx, ty); c.scale(ts, ts);
309
+ c.fillStyle = C.black; c.font = '700 96px "Space Grotesk"'; c.textBaseline = 'alphabetic';
310
+ const title = 'how does', title2 = 'ai learn?';
311
+ const nch = Math.floor(S(0.1, 1.0) * (title.length + title2.length + 1));
312
+ c.fillText(title.slice(0, nch), 0, 0); c.fillText(title2.slice(0, Math.max(0, nch - title.length - 1)), 0, 100);
313
+ c.restore();
314
+ if (hp >= 1) { // section marker hung under the header
315
+ const sect = t < 6.2 ? '1 data' : t < 10.6 ? '2 learn' : t < 12.9 ? '3 progress' : '';
316
+ if (sect) { c.fillStyle = C.red; c.fillRect(96, 124, 24, 24); c.fillStyle = C.black; c.font = '700 28px "Space Grotesk"'; c.fillText(sect, 130, 146); }
317
+ }
318
+
319
+ // ---------- takeaway ----------
320
+ const kp = S(13.3, 13.7);
321
+ if (kp > 0) {
322
+ c.save(); c.globalAlpha = 1; const dy = (1 - E.out(kp)) * 40;
323
+ c.fillStyle = C.black; c.font = '700 60px "Space Grotesk"'; c.textBaseline = 'alphabetic';
324
+ c.fillText('more examples', 96, 470 + dy);
325
+ exArrow(c, 560, 450 + dy, 700, 450 + dy, E.out(S(13.5, 13.8)), 14, C.red);
326
+ c.fillText('better guesses', 730, 470 + dy);
327
+ c.fillStyle = C.yellow; c.fillRect(96, 500 + dy, 1090 * E.out(S(13.6, 14.0)), 16);
328
+ c.restore();
329
+ }
330
+
331
+ // print it: per-colour misregistration is faked by a slight offset copy of the ink layer
332
+ const L = H.layer(W, HH), lc = L.getContext('2d'); lc.globalCompositeOperation = 'multiply';
333
+ PLATES.forEach((pl, i) => { const o = reg[PLATE_COLS[i]]; lc.drawImage(pl, o[0], o[1]); });
334
+ inkify(L, 21, 0.22, 0.004);
335
+ ctx.save(); ctx.globalCompositeOperation = 'multiply'; ctx.drawImage(L, 0, 0); ctx.restore();
336
+ const crease = (vert) => { const g = vert ? ctx.createLinearGradient(W / 2 - 4, 0, W / 2 + 10, 0) : ctx.createLinearGradient(0, HH / 2 - 8, 0, HH / 2 + 4);
337
+ g.addColorStop(0, 'rgba(255,250,235,0)'); g.addColorStop(0.45, 'rgba(255,250,235,0.18)'); g.addColorStop(0.55, 'rgba(70,50,30,0.14)'); g.addColorStop(1, 'rgba(70,50,30,0)'); ctx.fillStyle = g; vert ? ctx.fillRect(W / 2 - 4, 0, 14, HH) : ctx.fillRect(0, HH / 2 - 8, W, 12); };
338
+ crease(true); crease(false);
339
+ { // scuffs along the folds (as in the still)
340
+ const rs = H.rng(31); ctx.fillStyle = 'rgba(245,238,220,0.5)';
341
+ for (let i = 0; i < 260; i++) { const along = rs.range(0, 1); if (rs() < 0.5) ctx.fillRect(W / 2 + 2 + rs.gauss() * 1.2, along * HH, 1.2, rs.range(1, 4)); else ctx.fillRect(along * W, HH / 2 - 2 + rs.gauss() * 1.2, rs.range(1, 4), 1.2); } }
342
+ H.grain(ctx, W, HH, 0.06, 9 + Math.floor(t * 12), true);
343
+ H.vignette(ctx, W, HH, 0.18, '60,40,20');
344
+ };
345
+
346
+ registerStyle({
347
+ id: 'bauhaus',
348
+ name: 'Bauhaus Poster',
349
+ category: 'Art & Design Movements',
350
+ description: 'A 1920s Bauhaus exhibition poster: primary red, yellow and blue plus black on aged cream stock, a robot face built only from circles, squares, semicircles and triangles on a strict grid, with constructed geometric lettering and lithographic ink mottle.',
351
+ motion: 'Built like a workshop paste-up: grid rules draw out, the halo and head drop in and snap with a little overshoot, features stamp on one by one, then the constructed letters are set block by block and the type follows; in the hold the pupils swivel and the antenna waves pulse.',
352
+ fonts: ['700 22px "Space Grotesk"', '400 15px "Space Grotesk"', '800 20px "Syne"'],
353
+ frameT: 4.6,
354
+ duration: 5,
355
+ readsPixels: true,
356
+ explainerDuration: 14.5,
357
+ explainerNote: 'Told as one long Bayer-style info-design sheet the camera tracks along and finally pulls back from, with thick bar-and-triangle arrows, tags that drop onto what they name, stamped Space Grotesk counters and a red ring drawn round the key moment.',
358
+ explainer(ctx, W, HH, t) { explainBauhaus(ctx, W, HH, t); },
359
+ // Sound: a workshop table. Wooden blocks set down for every shape, type sorts tapped in for letters, the big
360
+ // sheet sliding along the drafting table between panels (with a stop clack), a numbering-machine counter and a
361
+ // small wooden marimba for "right", the 97% and the takeaway. All times copied from explainBauhaus() above.
362
+ explainerSound(k) {
363
+ const D = 14.5, E = H.ease, cl = H.clamp;
364
+ const S = (t, a, b) => cl((t - a) / (b - a), 0, 1);
365
+ const pan = (px) => cl((px / 1280) * 2 - 1, -1, 1) * 0.7;
366
+ // back-eased motion over [a, b] first reaches its final size at 37% of the way (then overshoots)
367
+ const backLand = (a, b) => a + (b - a) * 0.37;
368
+ // first time an eased progress over [a,b] reaches u
369
+ const when = (a, b, ease, u) => { for (let i = 0; i <= 400; i++) if (ease(i / 400) >= u - 1e-6) return a + ((b - a) * i) / 400; return b; };
370
+ // wooden block set down on the table: a knock with a little body
371
+ const block = (t, f, g, p, minor) => { k.play('tock', t, { f, gain: 0.55 * g, pan: p, minor }); k.noise(t, { dur: 0.05, color: 'brown', filter: 'lowpass', f: 600, gain: 0.25 * g, pan: p, minor }); };
372
+ // metal type sort tapped into the composing stick (no pitch, just a dry tap)
373
+ const sort = (t, g, p) => k.withMinor(() => { k.noise(t, { dur: 0.022, filter: 'bandpass', f: 2100, q: 1.4, gain: 0.26 * g, a: 0.001, pan: p }); k.tone(t, { f: 210, dur: 0.035, gain: 0.08 * g, pan: p }); });
374
+ // numbering machine: dry metal clack
375
+ const numb = (t, g, p) => k.withMinor(() => { k.noise(t, { dur: 0.024, filter: 'bandpass', f: 2600, q: 1.6, gain: 0.3 * g, a: 0.001, pan: p }); k.tone(t, { f: 560, type: 'triangle', dur: 0.03, gain: 0.06 * g, pan: p }); });
376
+ // the long sheet sliding along the drafting table, ending on a wooden stop
377
+ const slide = (t, dur, g, stop) => {
378
+ k.noise(t, { dur: dur + 0.1, color: 'pink', filter: 'bandpass', f: [[0, 260], [dur * 0.5, 620], [dur, 300]], q: 0.8, gain: 0.2 * g, a: dur * 0.45 });
379
+ if (stop) block(t + dur, 260, 0.8 * g, 0, false);
380
+ };
381
+ // small wooden marimba bar: soft mallet, short ring (kept at or under ~1 kHz)
382
+ const mar = (t, n, g, p, minor) => { const f = k.hz(n);
383
+ k.tone(t, { f, dur: 0.75, gain: 0.2 * g, a: 0.003, pan: p, verb: 0.12, minor });
384
+ if (f * 4 < 2400) k.tone(t, { f: f * 4, dur: 0.07, gain: 0.03 * g, a: 0.002, pan: p, minor });
385
+ k.noise(t, { dur: 0.018, filter: 'lowpass', f: 1400, gain: 0.12 * g, pan: p, minor }); };
386
+
387
+ k.bed('room', 0, D, { gain: 0.35 });
388
+
389
+ // ---- panel 0: rule draws down (0-0.6), red disc snaps in (back 0.25-0.85), title is set letter by letter (0.1-1.0)
390
+ k.noise(0.02, { dur: 0.55, color: 'pink', filter: 'bandpass', f: [[0, 500], [0.55, 300]], q: 0.7, gain: 0.08, a: 0.05, pan: pan(63), minor: true });
391
+ block(backLand(0.25, 0.85), 300, 1, pan(980), false);
392
+ { const txt = 'how does ai learn?'; let last = -1;
393
+ for (let n = 1; n <= txt.length; n++) { const t = 0.1 + (n / txt.length) * 0.9; if (txt[n - 1] === ' ' || t - last < 0.1) continue; sort(t, 1, pan(120 + (n % 9) * 45)); last = t; } }
394
+ block(when(0.6, 1.0, E.out, 0.95), 640, 0.6, pan(1160), true); // yellow bar
395
+ block(when(0.7, 1.1, E.out, 0.95), 520, 0.6, pan(840), true); // blue triangle
396
+ // title shrinks into the header (1.6-2.4): a soft card slide
397
+ k.noise(1.6, { dur: 0.7, color: 'pink', filter: 'bandpass', f: [[0, 400], [0.7, 900]], q: 0.7, gain: 0.07, a: 0.3, pan: -0.4, minor: true });
398
+
399
+ // ---- camera pans the sheet: 2.0-2.9, 5.8-6.6, 10.3-11.0
400
+ slide(2.0, 0.9, 1, true);
401
+ slide(5.8, 0.8, 1, true);
402
+ slide(10.3, 0.7, 1, true);
403
+
404
+ // ---- panel 1: DATA
405
+ // cards set onto the conveyor at 2.6 + 0.52 i (x = 40 in panel)
406
+ const cards = []; for (let i = 0; 2.6 + i * 0.52 < 5.55; i++) cards.push(2.6 + i * 0.52);
407
+ cards.forEach((tc, i) => block(tc, 430 + (i % 2) * 70, 0.6, pan(40), true));
408
+ block(backLand(3.3, 3.6), 560, 0.5, pan(330), true); // "training data" tag
409
+ // counter n = S(2.9,5.6)^3 * 1e6, shown from 3.1: numbering clacks speeding up, not on top of card knocks
410
+ for (let t = 3.15; t < 5.55; ) { const s = S(t, 2.9, 5.6); if (!cards.some((c) => t > c - 0.08 && t < c + 0.09)) numb(t, 0.7 + 0.4 * s, pan(320)); t += 0.16 - 0.075 * s; }
411
+ k.play('stamp', 5.6, { gain: 0.7, pan: pan(320) }); // 1,000,000 lands
412
+
413
+ // ---- panel 2: GUESS / CHECK / ADJUST
414
+ k.noise(6.4, { dur: 0.45, color: 'pink', filter: 'bandpass', f: [[0, 700], [0.45, 350]], q: 0.8, gain: 0.1, a: 0.08, pan: pan(660), minor: true }); // cat card slides in
415
+ block(backLand(6.9, 7.25), 470, 0.9, pan(760), true); // guess circle and "dog?" tag land together
416
+ // the wrong guess: red X (7.55-7.75) — a hard block and a low clashing marimba pair
417
+ k.play('stamp', 7.58, { gain: 0.8, pan: pan(648) });
418
+ mar(7.6, 'E3', 1.1, pan(648)); mar(7.6, 'F3', 1.0, pan(648));
419
+ // red ring drawn round the wrong guess (7.6-8.0): a ruling pen
420
+ k.noise(7.62, { dur: 0.4, color: 'pink', filter: 'bandpass', f: [[0, 900], [0.2, 1400], [0.4, 900]], q: 0.9, gain: 0.07, a: 0.06, pan: pan(585), minor: true });
421
+ // error square flies from check back to the dials (8.0-8.6), "error" tag appears on landing
422
+ k.noise(8.0, { dur: 0.6, color: 'pink', filter: 'bandpass', f: [[0, 300], [0.3, 800], [0.6, 300]], q: 1, gain: 0.12, a: 0.25, pan: pan(700) });
423
+ block(8.6, 330, 0.9, pan(300), false);
424
+ block(backLand(8.1, 8.45), 600, 0.6, pan(770), true); // adjust triangle
425
+ // dials ratchet round (inOut 8.4-9.2): detents, at least 90 ms apart
426
+ for (let i = 1, lt = 8.6; i <= 7; i++) { const t = when(8.4, 9.2, E.inOut, i / 7); if (t - lt < 0.09) continue; lt = t; k.play('click', t, { f: 1200, gain: 0.7, pan: pan(300), minor: true }); k.play('tock', t + 0.005, { f: 900 - i * 30, gain: 0.25, pan: pan(300), minor: true }); }
427
+ block(backLand(9.35, 9.6), 650, 0.5, pan(545), true); // "cat" tag
428
+ // the correction: check mark draws (9.6-9.85), face turns yellow — a rising wooden phrase
429
+ mar(9.62, 'C5', 0.9, pan(618)); mar(9.72, 'G5', 0.9, pan(618)); mar(9.72, 'C4', 0.6, pan(618));
430
+
431
+ // ---- panel 3: PROGRESS
432
+ block(10.8, 340, 0.6, pan(1000), true); // 61% set
433
+ // bars rise one by one at 10.9 + 0.14 i: an ascending wooden scale
434
+ const bars = ['C4', 'D4', 'E4', 'G4', 'A4', 'C5', 'D5', 'E5', 'G5', 'A5'].map((n, i) => { const t = 10.9 + i * 0.14 + 0.02; mar(t, n, 0.32, pan(150 + i * 66), true); return t; });
435
+ // accuracy 61 -> 97 (inOut over 10.9-12.3, changing all the way): one counter clack halfway between bar notes,
436
+ // so bar and number alternate like an escapement; the number is still rolling at each of these
437
+ bars.forEach((b) => { if (b + 0.07 < 12.25) numb(b + 0.07, 1.0, pan(1000)); });
438
+ // 97%: the big hit, then the red ring is drawn round it (12.3-12.7)
439
+ k.play('impact', 12.3, { gain: 1.2, pan: pan(1000) });
440
+ ['C4', 'E4', 'G4', 'C5'].forEach((n, i) => mar(12.31 + i * 0.012, n, 0.9, pan(1000) + (i - 1.5) * 0.1));
441
+ k.noise(12.34, { dur: 0.4, color: 'pink', filter: 'bandpass', f: [[0, 900], [0.2, 1400], [0.4, 900]], q: 0.9, gain: 0.07, a: 0.06, pan: pan(1005), minor: true });
442
+
443
+ // ---- pull back over the whole sheet (12.9-13.7), takeaway drops in (13.3-13.7), red arrow (13.5-13.8), yellow rule (13.6-14.0)
444
+ slide(12.9, 0.8, 0.8, false);
445
+ mar(13.48, 'G4', 0.6, -0.2, true); mar(13.48, 'D5', 0.5, 0.2, true); k.noise(13.48, { dur: 0.05, color: 'brown', filter: 'lowpass', f: 600, gain: 0.2, minor: true }); // takeaway lands
446
+ ['C4', 'G4', 'C5', 'E5'].forEach((n, i) => mar(13.8 + i * 0.05, n, 0.8 - i * 0.08, (i - 1.5) * 0.25)); // resolves as the arrow lands
447
+ k.noise(13.62, { dur: 0.4, color: 'pink', filter: 'bandpass', f: [[0, 350], [0.4, 650]], q: 0.8, gain: 0.08, a: 0.1, minor: true }); // yellow rule runs out
448
+ },
449
+ draw(ctx, W, HH, t) {
450
+ const ease = H.ease.out, back = H.ease.back;
451
+ const P = (d, dur = 0.7) => H.clamp((t - d) / dur, 0, 1);
452
+
453
+ // ---------- paper ----------
454
+ const paper = ctx.getImageData(0, 0, W, HH), pd = paper.data;
455
+ const lo = cachedField('lo', W, HH, 11, 24, 4), fib = cachedField('fib', W, HH, 12, 2, 2, 3.5, 0.5), r0 = H.rng(5);
456
+ const base = H.hex(C.cream), tan = H.hex('#c9ab78');
457
+ for (let y = 0, p = 0; y < HH; y++) for (let x = 0; x < W; x++, p++) {
458
+ const ex = Math.min(x, W - x) / W, ey = Math.min(y, HH - y) / HH;
459
+ const edge = Math.pow(1 - H.clamp(Math.min(ex * 3.2, ey * 2.2) + lo[p] * 0.15, 0, 1), 3);
460
+ const k = 0.35 * edge + 0.12 * Math.max(0, lo[p]);
461
+ const s = 1 + fib[p] * 0.035 + (r0() - 0.5) * 0.04;
462
+ const i = p * 4;
463
+ pd[i] = (base[0] + (tan[0] - base[0]) * k) * s; pd[i + 1] = (base[1] + (tan[1] - base[1]) * k) * s; pd[i + 2] = (base[2] + (tan[2] - base[2]) * k) * s; pd[i + 3] = 255;
464
+ }
465
+ ctx.putImageData(paper, 0, 0);
466
+ // foxing spots
467
+ const rf = H.rng(77);
468
+ for (let i = 0; i < 26; i++) {
469
+ const x = rf.range(0, W), y = rf.range(0, HH), rr = rf.range(2, 10);
470
+ const g = ctx.createRadialGradient(x, y, 0, x, y, rr);
471
+ g.addColorStop(0, 'rgba(140,90,40,0.22)'); g.addColorStop(1, 'rgba(140,90,40,0)');
472
+ ctx.fillStyle = g; ctx.beginPath(); ctx.arc(x, y, rr, 0, 7); ctx.fill();
473
+ }
474
+
475
+ // ---------- ink layer (knockout composition, per-colour misregistration) ----------
476
+ const L = H.layer(W, HH), c = L.getContext('2d');
477
+ const reg = { yellow: [2, -1], red: [-1.5, 1], blue: [1, 2], black: [0, 0] };
478
+ const ink = (col, fn) => { c.save(); c.translate(reg[col][0], reg[col][1]); c.fillStyle = C[col]; c.strokeStyle = C[col]; fn(); c.restore(); };
479
+
480
+ const cx = 470, cy = 360; // face centre
481
+ // grid rules
482
+ ink('black', () => {
483
+ const a = ease(P(0.0, 0.8));
484
+ c.fillRect(56, 56, 14, (HH - 112) * a); // left rule
485
+ c.fillRect(56, HH - 70, (W - 112) * a, 14); // base rule
486
+ c.fillRect(760, 56, 6, 470 * a); // column divider
487
+ c.fillRect(760, 520, 480 * a, 6);
488
+ });
489
+ ink('black', () => {
490
+ // diagonal construction rule running behind the figure into the halo
491
+ const s = ease(P(0.1, 0.9)); c.save(); c.translate(70, HH - 70); c.rotate(-Math.PI * 0.3); c.fillRect(0, -5, 640 * s, 10); c.restore();
492
+ });
493
+ // big yellow disc (halo)
494
+ ink('yellow', () => { const s = back(P(0.2)); c.beginPath(); c.arc(cx + 60, cy - 50, 235 * s, 0, 7); c.fill(); });
495
+ // red semicircle shoulders
496
+ ink('red', () => {
497
+ const s = ease(P(0.5)); c.beginPath(); c.arc(cx, HH - 70, 250, Math.PI, 0); c.closePath();
498
+ c.save(); c.beginPath(); c.rect(0, HH - 70 - 250 * s, W, 250 * s + 1); c.clip();
499
+ c.beginPath(); c.arc(cx, HH - 70, 250, Math.PI, 0); c.closePath(); c.fill(); c.restore();
500
+ });
501
+ // neck
502
+ ink('black', () => { const s = ease(P(0.6)); c.fillRect(cx - 50, 520, 100, 60 * s); });
503
+ ink('yellow', () => { if (P(0.9) > 0) { c.fillRect(cx - 50, 538, 100, 8); c.fillRect(cx - 50, 556, 100, 8); } });
504
+ // head: blue square
505
+ const hs = 300, hx = cx - hs / 2, hy = 220 - (1 - ease(P(0.35))) * 620;
506
+ ink('blue', () => { c.fillRect(hx, hy, hs, hs); });
507
+ // ears: semicircles
508
+ ink('red', () => { const s = back(P(0.9)); c.beginPath(); c.arc(hx, hy + 150, 56 * s, Math.PI / 2, Math.PI * 1.5); c.closePath(); c.fill(); });
509
+ ink('black', () => { const s = back(P(1.0)); c.beginPath(); c.arc(hx + hs, hy + 150, 56 * s, -Math.PI / 2, Math.PI / 2); c.closePath(); c.fill(); });
510
+ // antenna
511
+ ink('black', () => { const s = ease(P(1.1)); c.fillRect(cx - 6, hy - 75 * s, 12, 75 * s); });
512
+ ink('red', () => { const s = back(P(1.4)); c.beginPath(); c.arc(cx, hy - 82, 24 * s, 0, 7); c.fill(); });
513
+ // radio waves: concentric semicircle arcs (pulse with t)
514
+ ink('black', () => {
515
+ const ph = (t * 0.6) % 1;
516
+ c.lineWidth = 9; c.lineCap = 'butt';
517
+ for (let k = 0; k < 3; k++) {
518
+ const rr = 44 + k * 22 + ph * 22; const al = H.clamp(P(1.6 + k * 0.15) * (k === 2 ? 1 - ph : 1), 0, 1);
519
+ if (al <= 0) continue; c.globalAlpha = al;
520
+ c.beginPath(); c.arc(cx, hy - 82, rr, -Math.PI * 0.95, -Math.PI * 0.62); c.stroke();
521
+ c.beginPath(); c.arc(cx, hy - 82, rr, -Math.PI * 0.38, -Math.PI * 0.05); c.stroke();
522
+ }
523
+ c.globalAlpha = 1;
524
+ });
525
+ // eyes
526
+ const look = Math.sin(t * 1.3) * 0.5 + 0.5; // 0..1 -> look right
527
+ ink('yellow', () => { const s = back(P(1.2)); c.beginPath(); c.arc(hx + 85, hy + 105, 52 * s, 0, 7); c.fill(); });
528
+ ink('red', () => { const s = back(P(1.3)); c.fillRect(hx + hs - 85 - 52 * s, hy + 105 - 52 * s, 104 * s, 104 * s); });
529
+ ink('black', () => {
530
+ const s = back(P(1.5)), dx = H.lerp(-8, 18, look);
531
+ c.beginPath(); c.arc(hx + 85 + dx, hy + 105, 22 * s, 0, 7); c.fill();
532
+ c.beginPath(); c.arc(hx + hs - 85 + dx, hy + 105, 22 * s, 0, 7); c.fill();
533
+ });
534
+ // nose: yellow triangle
535
+ ink('yellow', () => { const s = back(P(1.6)); c.beginPath(); c.moveTo(cx - 28 * s, hy + 150); c.lineTo(cx + 28 * s, hy + 150); c.lineTo(cx, hy + 150 + 50 * s); c.closePath(); c.fill(); });
536
+ // mouth grille
537
+ ink('black', () => {
538
+ const s = ease(P(1.7)); c.fillRect(cx - 95, hy + 222, 190 * s, 46);
539
+ });
540
+ ink('blue', () => { const s = P(1.9); for (let i = 0; i < 5; i++) if (s > i / 5) c.fillRect(cx - 78 + i * 34, hy + 230, 14, 30); });
541
+
542
+ // ---------- right column: lettering ----------
543
+ ink('black', () => {
544
+ // constructed letters are set one by one, each dropped onto the baseline like a block of type
545
+ let x = 790; const base = 340, xh = 90, sw = 23;
546
+ [...'robot'].forEach((ch, i) => {
547
+ const p = P(1.95 + i * 0.11, 0.2);
548
+ c.save(); c.globalAlpha = p > 0 ? 1 : 0; c.translate(0, -(1 - back(p)) * 40);
549
+ const adv = letter(c, ch, x, base, xh, sw); c.restore();
550
+ x += adv + 12;
551
+ });
552
+ });
553
+ ink('red', () => {
554
+ const s = back(P(2.35, 0.5)); c.fillRect(792, 380, 120 * s, 120 * s);
555
+ });
556
+ ink('black', () => {
557
+ c.font = '700 22px "Space Grotesk"'; c.textBaseline = 'alphabetic';
558
+ c.globalAlpha = P(2.55, 0.25); c.fillText('a new form', 932, 404);
559
+ c.globalAlpha = P(2.65, 0.25); c.fillText('for a new mind', 932, 430);
560
+ c.font = '400 15px "Space Grotesk"';
561
+ c.globalAlpha = P(2.8, 0.25); c.fillText('ausstellung · exhibition', 932, 466);
562
+ c.globalAlpha = P(2.88, 0.25); c.fillText('09.10 — 31.12.2026', 932, 488);
563
+ c.font = '800 20px "Syne"';
564
+ c.globalAlpha = P(2.45, 0.25); c.fillText('nr. 4', 1170, 100);
565
+ c.globalAlpha = 1;
566
+ });
567
+ ink('blue', () => { const s = ease(P(2.4, 0.5)); c.beginPath(); c.arc(1185, 175, 40 * s, Math.PI / 2, Math.PI * 1.5); c.closePath(); c.fill(); });
568
+ ink('yellow', () => { const s = ease(P(2.5, 0.5)); c.fillRect(1190, 135, 40 * s, 80); });
569
+ // vertical rotated label on left rule
570
+ ink('black', () => {
571
+ c.save(); c.translate(100, 330); c.rotate(-Math.PI / 2); c.font = '700 22px "Space Grotesk"'; c.globalAlpha = P(3.0, 0.3);
572
+ c.fillText('maschine und mensch', 0, 0); c.restore();
573
+ });
574
+ ink('red', () => { c.fillRect(84, 56, 30, 30 * ease(P(3.1, 0.3))); });
575
+
576
+ inkify(L, 21, 0.22, 0.004);
577
+ ctx.save(); ctx.globalCompositeOperation = 'multiply'; ctx.drawImage(L, 0, 0); ctx.restore();
578
+
579
+ // ---------- finish: fold creases, wear, grain ----------
580
+ const crease = (x0, y0, x1, y1, wdt) => {
581
+ const g = ctx.createLinearGradient(x0 - (y1 - y0 ? wdt : 0), y0 - (y1 - y0 ? 0 : wdt), x0 + (y1 - y0 ? wdt : 0), y0 + (y1 - y0 ? 0 : wdt));
582
+ g.addColorStop(0, 'rgba(255,250,235,0)'); g.addColorStop(0.45, 'rgba(255,250,235,0.18)'); g.addColorStop(0.55, 'rgba(70,50,30,0.14)'); g.addColorStop(1, 'rgba(70,50,30,0)');
583
+ ctx.fillStyle = g;
584
+ if (x0 === x1) ctx.fillRect(x0 - wdt, 0, wdt * 2, HH); else ctx.fillRect(0, y0 - wdt, W, wdt * 2);
585
+ };
586
+ crease(W / 2 + 3, 0, W / 2 + 3, HH, 7);
587
+ crease(0, HH / 2 - 2, W, HH / 2 - 2, 6);
588
+ // scuffs along the folds
589
+ const rs = H.rng(31); ctx.fillStyle = 'rgba(245,238,220,0.5)';
590
+ for (let i = 0; i < 260; i++) { const along = rs.range(0, 1); if (rs() < 0.5) ctx.fillRect(W / 2 + 2 + rs.gauss() * 1.2, along * HH, 1.2, rs.range(1, 4)); else ctx.fillRect(along * W, HH / 2 - 2 + rs.gauss() * 1.2, rs.range(1, 4), 1.2); }
591
+ H.grain(ctx, W, HH, 0.07, 9 + Math.floor(t * 12), true);
592
+ H.vignette(ctx, W, HH, 0.18, '60,40,20');
593
+ },
594
+ });
595
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "id": 74,
3
+ "name": "Bauhaus Poster",
4
+ "nameZh": "包豪斯海报",
5
+ "family": "Art & Design Movements",
6
+ "familyZh": "艺术与设计流派",
7
+ "description": "A 1920s Bauhaus exhibition poster: primary red, yellow and blue plus black on aged cream stock, a robot face built only from circles, squares, semicircles and triangles on a strict grid, with constructed geometric lettering and lithographic ink mottle.",
8
+ "motionNotes": "Motion: Built like a workshop paste-up: grid rules draw out, the halo and head drop in and snap with a little overshoot, features stamp on one by one, then the constructed letters are set block by block and the type follows; in the hold the pupils swivel and the antenna waves pulse.",
9
+ "explainerNotes": "Explainer: Told as one long Bayer-style info-design sheet the camera tracks along and finally pulls back from, with thick bar-and-triangle arrows, tags that drop onto what they name, stamped Space Grotesk counters and a red ring drawn round the key moment.",
10
+ "code": "code.js",
11
+ "registeredAs": "bauhaus",
12
+ "source": "https://www.futurepedia.io/resources/ai-style-atlas/view"
13
+ }