@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": 66,
3
+ "name": "Hidden-Line Wireframe",
4
+ "nameZh": "隐藏线框图",
5
+ "family": "Dimensional",
6
+ "familyZh": "立体空间",
7
+ "description": "Vector-display 3D: a perspective wire-mesh landscape with true hidden-line removal (back-to-front quads filled with the night before stroking), a wireframe moon, phosphor-cyan lines with bloom on deep navy, and HUD coordinate labels.",
8
+ "motionNotes": "Motion: HUD brackets snap on, the wireframe moon traces itself, then the hidden-line mesh is scanned in row by row from the camera to the horizon behind a bright scan front; markers lock on and labels type out while the camera glides forward and the scan keeps sweeping.",
9
+ "explainerNotes": "Explainer: Learning is shown as descent over the hidden-line “loss landscape”: the camera flies the mesh from a data-feed HUD streaming into the wireframe-sphere model, down to an amber “model weights” marker whose error becomes a dashed downhill vector, then follows it into the glowing basin; labels are bracketed HUD tags that type on, numbers are big Space Mono readouts.",
10
+ "code": "code.js",
11
+ "registeredAs": "wireframe-terrain",
12
+ "source": "https://www.futurepedia.io/resources/ai-style-atlas/view"
13
+ }
@@ -0,0 +1,548 @@
1
+ {
2
+ const K = '#151515';
3
+ const PAL = { pink: '#f9c3d2', mint: '#a9e5d0', lilac: '#cbb8f4', butter: '#fff0a6', cream: '#fff8ec', magenta: '#ff4f9b', blue: '#2b62ff', yellow: '#ffd02e', teal: '#00b2a0', red: '#ff5a3c' };
4
+
5
+ // filled + outlined + hard drop shadow
6
+ const solid = (c, path, fill, sh = 10, lw = 5) => {
7
+ c.save(); c.translate(sh, sh); c.fillStyle = K; c.fill(path); c.restore();
8
+ c.fillStyle = fill; c.fill(path); c.lineWidth = lw; c.strokeStyle = K; c.lineJoin = 'round'; c.stroke(path);
9
+ };
10
+ const squigglePath = (x, y, len, amp, waves, ang, ph = 0, frac = 1) => {
11
+ const p = new Path2D(), ca = Math.cos(ang), sa = Math.sin(ang);
12
+ for (let i = 0; i <= Math.round(80 * frac); i++) {
13
+ const u = i / 80, lx = u * len, ly = Math.sin(u * waves * Math.PI * 2 + ph) * amp;
14
+ const X = x + lx * ca - ly * sa, Y = y + lx * sa + ly * ca;
15
+ i ? p.lineTo(X, Y) : p.moveTo(X, Y);
16
+ }
17
+ return p;
18
+ };
19
+ const zigzagPath = (x, y, len, amp, n, ang, frac = 1) => {
20
+ const p = new Path2D(), ca = Math.cos(ang), sa = Math.sin(ang), f = frac * n;
21
+ for (let i = 0; i <= Math.ceil(f); i++) { const ii = Math.min(i, f), i0 = Math.floor(ii), fr = ii - i0, ya = i0 % 2 ? -amp : amp, yb = (i0 + 1) % 2 ? -amp : amp; const lx = (ii / n) * len, ly = ya + (yb - ya) * fr; const X = x + lx * ca - ly * sa, Y = y + lx * sa + ly * ca; i ? p.lineTo(X, Y) : p.moveTo(X, Y); }
22
+ return p;
23
+ };
24
+ const strokeOutlined = (c, path, col, w, ow = 4, sh = 8) => {
25
+ c.lineCap = 'round'; c.lineJoin = 'round';
26
+ c.save(); c.translate(sh, sh); c.strokeStyle = K; c.lineWidth = w + ow * 2; c.stroke(path); c.restore();
27
+ c.strokeStyle = K; c.lineWidth = w + ow * 2; c.stroke(path);
28
+ c.strokeStyle = col; c.lineWidth = w; c.stroke(path);
29
+ };
30
+ const terrazzo = (c, path, seed, base = PAL.cream) => {
31
+ c.save(); c.clip(path); c.fillStyle = base; c.fillRect(0, 0, 1280, 720);
32
+ const r = H.rng(seed), cols = [PAL.magenta, PAL.blue, PAL.yellow, PAL.teal, K, PAL.pink, PAL.lilac, PAL.red];
33
+ const bb = { x0: 0, y0: 0, x1: 1280, y1: 720 };
34
+ for (let i = 0; i < 2400; i++) {
35
+ const x = r.range(bb.x0, bb.x1), y = r.range(bb.y0, bb.y1);
36
+ if (!c.isPointInPath(path, x, y)) continue;
37
+ const s = r.range(3, 11) * (r() < 0.08 ? 2 : 1), n = r.int(3, 6), a0 = r.range(0, 7);
38
+ c.fillStyle = r.pick(cols); c.beginPath();
39
+ for (let k = 0; k < n; k++) { const a = a0 + (k / n) * Math.PI * 2 + r.range(-0.3, 0.3), rr = s * r.range(0.5, 1); k ? c.lineTo(x + Math.cos(a) * rr, y + Math.sin(a) * rr) : c.moveTo(x + Math.cos(a) * rr, y + Math.sin(a) * rr); }
40
+ c.closePath(); c.fill();
41
+ }
42
+ c.restore();
43
+ };
44
+
45
+ // ===================== EXPLAINER: "How does AI learn?" =====================
46
+ // Memphis cut-out animation on twos: scenes change with a striped band that swipes across, arrows are fat
47
+ // outlined shapes, counters are stickers that pop, emphasis is a spiky starburst.
48
+ const roundRect = (x, y, w, h, r) => { const p = new Path2D(); p.moveTo(x + r, y); p.arcTo(x + w, y, x + w, y + h, r); p.arcTo(x + w, y + h, x, y + h, r); p.arcTo(x, y + h, x, y, r); p.arcTo(x, y, x + w, y, r); p.closePath(); return p; };
49
+ const bubble = (w, h, tail) => { // tail: [x, y] of the tip relative to centre
50
+ const p = new Path2D(), r = 34, x = -w / 2, y = -h / 2;
51
+ p.moveTo(x + r, y); p.arcTo(x + w, y, x + w, y + h, r); p.arcTo(x + w, y + h, x, y + h, r);
52
+ if (tail) { p.lineTo(tail[0] + 40, y + h); p.lineTo(tail[0], tail[1]); p.lineTo(tail[0] - 10, y + h); }
53
+ p.arcTo(x, y + h, x, y, r); p.arcTo(x, y, x + w, y, r); p.closePath(); return p;
54
+ };
55
+ const burst = (n, r0, r1) => { const p = new Path2D(); for (let i = 0; i < n * 2; i++) { const a = i / (n * 2) * Math.PI * 2, r = i % 2 ? r0 : r1; i ? p.lineTo(Math.cos(a) * r, Math.sin(a) * r) : p.moveTo(Math.cos(a) * r, Math.sin(a) * r); } p.closePath(); return p; };
56
+ const fatArrow = (c, x0, y0, x1, y1, p, col, w = 22) => { // outlined chunky arrow with hard shadow
57
+ if (p <= 0) return; const a = Math.atan2(y1 - y0, x1 - x0), l = Math.hypot(x1 - x0, y1 - y0) * p, hw = w * 1.3, hl = w * 1.6;
58
+ const path = new Path2D(); path.moveTo(0, -w / 2); path.lineTo(Math.max(0, l - hl), -w / 2); path.lineTo(Math.max(0, l - hl), -hw); path.lineTo(l, 0); path.lineTo(Math.max(0, l - hl), hw); path.lineTo(Math.max(0, l - hl), w / 2); path.lineTo(0, w / 2); path.closePath();
59
+ c.save(); c.translate(x0, y0); c.rotate(a); solid(c, path, col, 6, 4); c.restore();
60
+ };
61
+ const face = (c, kind, x, y, s) => { // chunky sticker card with a cat or dog face
62
+ const card = roundRect(x - s / 2, y - s / 2, s, s, s * 0.14); solid(c, card, PAL.cream, 6, 4);
63
+ c.lineWidth = 3.5; c.strokeStyle = K;
64
+ if (kind === 'cat') {
65
+ const p = new Path2D(); p.moveTo(x - s * 0.3, y + s * 0.02); p.lineTo(x - s * 0.28, y - s * 0.34); p.lineTo(x - s * 0.08, y - s * 0.18); p.lineTo(x + s * 0.08, y - s * 0.18); p.lineTo(x + s * 0.28, y - s * 0.34); p.lineTo(x + s * 0.3, y + s * 0.02); p.arc(x, y + s * 0.04, s * 0.3, 0, Math.PI); p.closePath();
66
+ c.fillStyle = PAL.yellow; c.fill(p); c.stroke(p);
67
+ c.fillStyle = K; c.beginPath(); c.arc(x - s * 0.1, y + s * 0.02, s * 0.04, 0, 7); c.arc(x + s * 0.1, y + s * 0.02, s * 0.04, 0, 7); c.fill();
68
+ c.fillStyle = PAL.magenta; c.beginPath(); c.moveTo(x - s * 0.05, y + s * 0.1); c.lineTo(x + s * 0.05, y + s * 0.1); c.lineTo(x, y + s * 0.16); c.closePath(); c.fill();
69
+ } else {
70
+ c.fillStyle = PAL.blue; for (const sd of [-1, 1]) { c.beginPath(); c.ellipse(x + sd * s * 0.28, y + s * 0.02, s * 0.1, s * 0.2, sd * -0.3, 0, 7); c.fill(); c.stroke(); }
71
+ c.fillStyle = PAL.pink; c.beginPath(); c.arc(x, y + s * 0.02, s * 0.25, 0, 7); c.fill(); c.stroke();
72
+ c.fillStyle = K; c.beginPath(); c.arc(x - s * 0.09, y - s * 0.02, s * 0.035, 0, 7); c.arc(x + s * 0.09, y - s * 0.02, s * 0.035, 0, 7); c.fill();
73
+ c.beginPath(); c.ellipse(x, y + s * 0.1, s * 0.06, s * 0.045, 0, 0, 7); c.fill();
74
+ }
75
+ };
76
+ const tag = (c, txt, x, y, col, size = 22, rot = 0, halo = 0) => { c.save(); c.translate(x, y); c.rotate(rot); c.font = `700 ${size}px "Fredoka"`; const w = c.measureText(txt).width + size; if (halo) { const hp = roundRect(-w / 2 - halo, -size * 0.75 - halo, w + halo * 2, size * 1.5 + halo * 2, size * 0.75 + halo); solid(c, hp, PAL.cream, 6, 3); } const p = roundRect(-w / 2, -size * 0.75, w, size * 1.5, size * 0.75); solid(c, p, col, 4, 3); c.fillStyle = K; c.textAlign = 'center'; c.textBaseline = 'middle'; c.fillText(txt, 0, 1); c.restore(); };
77
+ const chunky = (c, txt, x, y, size, col, ls = -4) => { c.save(); c.font = `400 ${size}px "Rubik Mono One"`; c.letterSpacing = ls + 'px'; c.textAlign = 'center'; c.textBaseline = 'middle'; c.lineJoin = 'round'; c.fillStyle = K; c.fillText(txt, x + size * 0.07, y + size * 0.07); c.lineWidth = Math.max(4, size * 0.09); c.strokeStyle = K; c.strokeText(txt, x, y); c.fillStyle = col; c.fillText(txt, x, y); c.restore(); c.letterSpacing = '0px'; };
78
+ const machine = (c, x, y, knobs, look, mood) => { // the model: a Memphis totem-computer with a funnel and three knobs
79
+ // feet
80
+ for (const sd of [-1, 1]) { const f = new Path2D(); f.arc(x + sd * 60, y + 140, 34, Math.PI, 0); f.closePath(); solid(c, f, PAL.blue, 6, 4); }
81
+ const body = roundRect(x - 115, y - 120, 230, 260, 26); solid(c, body, PAL.lilac, 12, 5);
82
+ c.save(); c.clip(body); c.fillStyle = 'rgba(21,21,21,0.5)'; for (let i = -10; i < 10; i++) { c.beginPath(); c.arc(x - 100 + (i % 5) * 50, y + 80 + Math.floor(i / 5) * 18, 3, 0, 7); c.fill(); } c.restore();
83
+ const scr = roundRect(x - 85, y - 92, 170, 110, 18); solid(c, scr, PAL.cream, 0, 4);
84
+ const dx = (look - 0.5) * 16;
85
+ c.fillStyle = K; c.beginPath(); c.arc(x - 34 + dx, y - 42, 12, 0, 7); c.arc(x + 34 + dx, y - 42, 12, 0, 7); c.fill();
86
+ c.lineWidth = 5; c.strokeStyle = K; c.lineCap = 'round'; c.beginPath(); if (mood > 0) c.arc(x + dx * 0.5, y - 20, 22, 0.2, Math.PI - 0.2); else if (mood < 0) c.arc(x + dx * 0.5, y + 2, 20, Math.PI + 0.3, -0.3); else { c.moveTo(x - 18, y - 6); c.lineTo(x + 18, y - 6); } c.stroke();
87
+ // knobs on the belly
88
+ knobs.forEach((a, i) => { const kx = x - 62 + i * 62, ky = y + 50; const kp = new Path2D(); kp.arc(kx, ky, 20, 0, Math.PI * 2); solid(c, kp, [PAL.magenta, PAL.teal, PAL.yellow][i], 4, 4); c.save(); c.translate(kx, ky); c.rotate(a); c.fillStyle = K; c.fillRect(-3, -18, 6, 16); c.restore(); });
89
+ // funnel on top
90
+ const fn = new Path2D(); fn.moveTo(x - 80, y - 210); fn.lineTo(x + 80, y - 210); fn.lineTo(x + 26, y - 122); fn.lineTo(x - 26, y - 122); fn.closePath();
91
+ solid(c, fn, PAL.yellow, 8, 5); c.save(); c.clip(fn); c.fillStyle = K; for (let i = -6; i < 6; i++) c.fillRect(x + i * 24, y - 220, 9, 110); c.restore(); c.lineWidth = 5; c.strokeStyle = K; c.stroke(fn);
92
+ };
93
+
94
+ // static per-scene ground: pastel split, bacterio dashes at hero strength, and a decor layer (terrazzo quarter-disc,
95
+ // dot-grid card, confetti, a squiggle) kept to corners and edges that no story element uses. Built once per scene.
96
+ const GROUNDS = {};
97
+ const confetti = (c, r, spots) => spots.forEach(([x, y], i) => {
98
+ const s = r.range(10, 17), kind = i % 4, col = [PAL.magenta, PAL.blue, PAL.yellow, PAL.teal, PAL.red, K][(i * 5 + 1) % 6];
99
+ c.save(); c.translate(x, y); c.rotate(r.range(0, 7)); const p = new Path2D();
100
+ if (kind <= 1) { p.moveTo(0, -s); p.lineTo(s * 0.9, s * 0.6); p.lineTo(-s * 0.9, s * 0.6); p.closePath(); c.fillStyle = col; c.fill(p); c.lineWidth = 3; c.strokeStyle = K; c.stroke(p); }
101
+ else if (kind === 2) { c.fillStyle = col; c.fillRect(-s * 0.9, -3.5, s * 1.8, 7); }
102
+ else { c.beginPath(); c.arc(0, 0, s * 0.45, 0, 7); c.fillStyle = col; c.fill(); c.lineWidth = 3; c.strokeStyle = K; c.stroke(); }
103
+ c.restore();
104
+ });
105
+ const dotCard = (c, x, y, w, h, col, rot = 0) => { c.save(); c.translate(x + w / 2, y + h / 2); c.rotate(rot); const p = new Path2D(); p.rect(-w / 2, -h / 2, w, h); solid(c, p, col, 8, 4); c.save(); c.clip(p); c.fillStyle = K; for (let yy = -h / 2 + 14; yy < h / 2 - 6; yy += 16) for (let xx = -w / 2 + 14; xx < w / 2 - 6; xx += 16) { c.beginPath(); c.arc(xx, yy, 3, 0, 7); c.fill(); } c.restore(); c.restore(); };
106
+ const quarter = (c, cx, cy, R, a0, seed) => { const p = new Path2D(); p.moveTo(cx, cy); p.arc(cx, cy, R, a0, a0 + Math.PI / 2); p.closePath(); c.save(); c.translate(10, 10); c.fillStyle = K; c.fill(p); c.restore(); terrazzo(c, p, seed); c.lineWidth = 5; c.strokeStyle = K; c.stroke(p); };
107
+ const gridCard = (c, x, y, w, h, col, rot) => { c.save(); c.translate(x + w / 2, y + h / 2); c.rotate(rot); const p = new Path2D(); p.rect(-w / 2, -h / 2, w, h); solid(c, p, col, 8, 4); c.save(); c.clip(p); c.strokeStyle = 'rgba(21,21,21,0.5)'; c.lineWidth = 2; for (let xx = -w / 2; xx < w / 2; xx += 24) { c.beginPath(); c.moveTo(xx, -h / 2); c.lineTo(xx, h / 2); c.stroke(); } for (let yy = -h / 2; yy < h / 2; yy += 24) { c.beginPath(); c.moveTo(-w / 2, yy); c.lineTo(w / 2, yy); c.stroke(); } c.restore(); c.lineWidth = 4; c.strokeStyle = K; c.stroke(p); c.restore(); };
108
+ function sceneGround(scene, grounds, W, HH) {
109
+ const key = scene + ':' + W + 'x' + HH;
110
+ if (GROUNDS[key]) return GROUNDS[key];
111
+ const L = H.layer(W, HH), c = L.getContext('2d');
112
+ c.fillStyle = grounds[0]; c.fillRect(0, 0, W, HH);
113
+ c.fillStyle = grounds[1]; c.beginPath(); c.moveTo(860, 0); c.lineTo(W, 0); c.lineTo(W, HH); c.lineTo(600, HH); c.closePath(); c.fill();
114
+ const rb = H.rng(3 + scene); c.fillStyle = 'rgba(21,21,21,0.55)';
115
+ for (let i = 0; i < 260; i++) { const x = rb.range(0, W), y = rb.range(0, HH), a = rb.range(0, Math.PI); c.save(); c.translate(x, y); c.rotate(a); c.beginPath(); c.ellipse(0, 0, rb.range(3, 7), 1.6, 0, 0, 7); c.fill(); c.restore(); }
116
+ const r = H.rng(40 + scene);
117
+ c.lineCap = 'round'; c.lineJoin = 'round';
118
+ if (scene === 1) {
119
+ quarter(c, 0, HH, 165, -Math.PI / 2, 21);
120
+ dotCard(c, 1010, 638, 240, 62, PAL.butter, -0.02);
121
+ strokeOutlined(c, squigglePath(430, 688, 230, 9, 3.5, -0.03), PAL.blue, 8, 3, 5);
122
+ confetti(c, r, [[40, 170], [78, 300], [36, 430], [1240, 40], [1150, 70], [1250, 150], [470, 40], [600, 640], [1260, 400]]);
123
+ } else if (scene === 2) {
124
+ quarter(c, W, HH, 165, Math.PI, 22);
125
+ dotCard(c, 1132, 22, 128, 84, PAL.pink, 0.04);
126
+ strokeOutlined(c, squigglePath(620, 690, 240, 10, 3, -0.04), PAL.magenta, 8, 3, 5);
127
+ c.strokeStyle = K; c.lineWidth = 6; c.stroke(zigzagPath(48, 200, 300, 10, 9, Math.PI / 2));
128
+ confetti(c, r, [[40, 640], [110, 690], [380, 670], [900, 640], [880, 40], [1060, 40], [1250, 210], [1240, 300], [440, 40]]);
129
+ } else if (scene === 3) {
130
+ quarter(c, W, HH, 150, Math.PI, 23);
131
+ gridCard(c, 430, 30, 230, 96, PAL.butter, -0.03);
132
+ strokeOutlined(c, squigglePath(30, 680, 210, 9, 3, -0.03), PAL.teal, 8, 3, 5);
133
+ confetti(c, r, [[720, 50], [780, 120], [1250, 60], [1180, 40], [40, 200], [60, 330], [850, 690], [700, 690]]);
134
+ } else {
135
+ quarter(c, W, 0, 160, Math.PI / 2, 24);
136
+ dotCard(c, 560, 652, 240, 50, PAL.mint, 0.02);
137
+ c.strokeStyle = K; c.lineWidth = 6; c.stroke(squigglePath(52, 190, 300, 12, 3, Math.PI / 2));
138
+ confetti(c, r, [[860, 40], [960, 90], [1210, 260], [1240, 380], [1210, 520], [40, 60 + 560], [470, 690], [1240, 660], [760, 40]]);
139
+ }
140
+ GROUNDS[key] = L; return L;
141
+ }
142
+
143
+ const explainMemphis = (ctx, W, HH, t) => {
144
+ const c = ctx, E = H.ease, cl = H.clamp;
145
+ const tq = Math.floor(t * 12) / 12; // on twos
146
+ const S = (a, b) => cl((tq - a) / (b - a), 0, 1);
147
+ const pop = (d, x, y, dur = 0.25) => { const s = E.back(S(d, d + dur)); if (s <= 0) return false; c.save(); c.translate(x, y); c.scale(s, s); c.translate(-x, -y); return true; };
148
+ const bob = (ph, a = 5) => Math.sin(tq * 2.4 + ph) * a;
149
+ const BANDS = [5.4, 9.8, 12.35], swap = (b) => b + 0.42;
150
+ const scene = tq < swap(BANDS[0]) ? 1 : tq < swap(BANDS[1]) ? 2 : tq < swap(BANDS[2]) ? 3 : 4;
151
+ const grounds = { 1: [PAL.pink, PAL.mint], 2: [PAL.butter, PAL.lilac], 3: [PAL.mint, PAL.pink], 4: [PAL.lilac, PAL.butter] }[scene];
152
+ c.drawImage(sceneGround(scene, grounds, W, HH), 0, 0);
153
+ const MX = 300, MY = 430; // machine position in scenes 1-2
154
+
155
+ // ---------- hook: big bubble, then it shrinks into a corner sticker ----------
156
+ const hp = E.inOut(S(1.7, 2.3));
157
+ {
158
+ const bp = S(0.1, 0.45); const x = H.lerp(640, 200, hp), y = H.lerp(340, 80, hp), sc = H.lerp(1, 0.42, hp), rot = H.lerp(-0.05, -0.06, hp);
159
+ if (bp > 0 && hp < 1) {
160
+ c.save(); c.translate(x, y); c.rotate(rot); c.scale(sc * E.back(bp), sc * E.back(bp));
161
+ solid(c, bubble(820, 300, hp < 0.5 ? [-200, 230] : null), PAL.yellow, 16, 6);
162
+ if (tq >= 0.45) chunky(c, 'HOW DOES', 0, -50, 84, PAL.magenta);
163
+ if (tq >= 0.6) chunky(c, 'AI LEARN?', 0, 60, 84, PAL.blue);
164
+ c.restore();
165
+ }
166
+ if (hp < 1) { strokeOutlined(c, squigglePath(80, 620, 260, 16, 3, -0.1, tq * 3, S(0.3, 0.9)), PAL.teal, 12, 4, 6); if (pop(0.5, 1120, 150)) { c.translate(1120, 150); c.rotate(tq); solid(c, burst(12, 50, 80), PAL.magenta, 8, 4); c.restore(); } }
167
+ }
168
+
169
+ // ---------- scene 1: data dropped into the funnel ----------
170
+ if (scene === 1 && tq > 2.0) {
171
+ if (pop(2.0, MX, MY, 0.3)) { machine(c, MX, MY + bob(0, 3), [0.4, -0.8, 1.2], 0.5 + 0.5 * Math.sin(tq * 3), 1); c.restore(); }
172
+ if (tq > 2.3) tag(c, 'MODEL', MX, MY + 200, PAL.butter, 28, -0.05);
173
+ // examples hop in from the right along arcs into the funnel
174
+ for (let i = 0; i < 12; i++) {
175
+ const u = (tq - 2.5 - i * 0.28) / 1.1; if (u < 0 || u > 1) continue;
176
+ const kind = H.rng(i * 9 + 4)() < 0.5 ? 'cat' : 'dog', sx = 1180 - (i % 3) * 120, sy = 560 - (i % 2) * 90;
177
+ const x = H.lerp(sx, MX, u), y = H.lerp(sy, MY - 230, u) - Math.sin(u * Math.PI) * 260, s = 92 * (1 - E.in(cl((u - 0.75) / 0.25, 0, 1)));
178
+ if (s < 8) continue;
179
+ c.save(); c.translate(x, y); c.rotate((1 - u) * (i % 2 ? 0.4 : -0.4)); face(c, kind, 0, 0, s); if (s > 60) tag(c, kind, 0, s * 0.58, kind === 'cat' ? PAL.yellow : PAL.mint, 28); c.restore();
180
+ }
181
+ fatArrow(c, 1000, 250, 520, 200, E.out(S(2.7, 3.1)), PAL.magenta, 20);
182
+ if (tq > 3.0) tag(c, 'TRAINING DATA', 800, 160, PAL.cream, 28, -0.08, 9);
183
+ // counter sticker pops every time it ticks
184
+ const cp = S(3.0, 5.2), n = cp < 1 ? Math.pow(cp, 3) * 1e6 : 1e6, beat = 1 + 0.06 * (Math.floor(tq * 12) % 2);
185
+ if (pop(2.9, 960, 520, 0.3)) {
186
+ c.translate(960, 520); c.rotate(0.05); c.scale(beat, beat);
187
+ const st = roundRect(-250, -70, 500, 140, 30); solid(c, st, PAL.cream, 10, 5);
188
+ chunky(c, Math.round(n).toLocaleString('en-US'), 0, -12, 64, PAL.red, -6);
189
+ c.font = '700 30px "Fredoka"'; c.fillStyle = K; c.textAlign = 'center'; c.fillText('EXAMPLES', 0, 50);
190
+ c.restore();
191
+ }
192
+ }
193
+
194
+ // ---------- scene 2: guess -> check -> adjust ----------
195
+ if (scene === 2) {
196
+ const t0 = swap(BANDS[0]), adj = E.inOut(S(8.3, 9.0)), right = tq >= 9.3;
197
+ const knobs = [H.lerp(0.4, -1.2, adj), H.lerp(-0.8, 0.9, adj), H.lerp(1.2, 0.1, adj)];
198
+ machine(c, MX, MY + bob(0, 3), knobs, right ? 0.9 : 0.8, tq < 7.4 ? 0 : right ? 1 : -1);
199
+ // new picture
200
+ if (pop(t0 + 0.1, 560, 470, 0.3)) { face(c, 'cat', 560, 470, 130); c.restore(); }
201
+ if (tq > t0 + 0.35) tag(c, 'NEW PICTURE', 560, 570, PAL.cream, 24, 0.04);
202
+ // speech bubble with the guess
203
+ const bx = 600, by = 200;
204
+ const say = (txt, col, d) => { const s = E.back(S(d, d + 0.25)); if (s <= 0) return false; c.save(); c.translate(bx, by); c.scale(s, s); solid(c, bubble(300, 130, [-110, 110]), PAL.cream, 8, 5); chunky(c, txt, 0, 4, 60, col); c.restore(); return true; };
205
+ if (!right && say('DOG?', PAL.blue, 6.7)) {
206
+ if (tq >= 7.4) { // CHECK: starburst + squiggly cross
207
+ c.save(); c.translate(bx + 200, by - 40); c.rotate(tq * 0.8); solid(c, burst(10, 44, 70), PAL.red, 6, 4); c.restore();
208
+ c.save(); c.translate(bx + 200, by - 40); c.lineCap = 'round'; c.strokeStyle = PAL.cream; c.lineWidth = 12; c.beginPath(); c.moveTo(-22, -22); c.lineTo(22, 22); c.moveTo(22, -22); c.lineTo(-22, 22); c.stroke(); c.restore();
209
+ tag(c, 'NOPE, IT’S A CAT!', bx + 20, by - 102, PAL.red, 26, -0.04);
210
+ }
211
+ }
212
+ if (right && say('CAT!', PAL.magenta, 9.3)) {
213
+ if (tq >= 9.6) { c.save(); c.translate(bx + 190, by - 40); solid(c, burst(10, 44, 66), PAL.teal, 6, 4); c.lineCap = 'round'; c.lineJoin = 'round'; c.strokeStyle = K; c.lineWidth = 11; c.beginPath(); c.moveTo(-22, 2); c.lineTo(-6, 18); c.lineTo(24, -18); c.stroke(); c.restore(); }
214
+ }
215
+ // ADJUST: a zigzag bolt runs back from the check to the knobs
216
+ if (tq >= 7.8 && tq < 9.3) { strokeOutlined(c, zigzagPath(bx + 190, by + 10, 480, 18, 10, 2.45, S(7.8, 8.2)), PAL.yellow, 11, 4, 6); if (tq > 8.2) tag(c, 'ERROR!', 520, 380, PAL.yellow, 26, 0.1); }
217
+ // the loop on the right: three patterned shapes chased by chunky arrows
218
+ const L = [['GUESS', 1000, 170, 'circle', PAL.magenta], ['CHECK', 1160, 400, 'tri', PAL.teal], ['ADJUST', 900, 470, 'square', PAL.blue]], act = tq < 7.4 ? 0 : tq < 8.2 ? 1 : tq < 9.3 ? 2 : Math.floor((tq - 9.3) * 3) % 3;
219
+ L.forEach(([s, x, y, sh, col], i) => {
220
+ if (!pop(t0 + 0.2 + i * 0.12, x, y, 0.25)) return;
221
+ const k = i === act && tq > 6.7 ? 1.12 + 0.04 * Math.sin(tq * 12) : 1; c.translate(x, y); c.scale(k, k); c.translate(-x, -y);
222
+ const p = new Path2D(); if (sh === 'circle') p.arc(x, y, 62, 0, 7); else if (sh === 'tri') { p.moveTo(x, y - 70); p.lineTo(x + 70, y + 52); p.lineTo(x - 70, y + 52); p.closePath(); } else p.rect(x - 60, y - 55, 120, 110);
223
+ solid(c, p, col, 8, 5);
224
+ c.save(); c.clip(p); c.fillStyle = 'rgba(21,21,21,0.35)'; for (let a = -4; a < 5; a++) for (let b = -4; b < 5; b++) { c.beginPath(); c.arc(x + a * 18, y + b * 18, 2.6, 0, 7); c.fill(); } c.restore();
225
+ tag(c, s, x, y + (sh === 'tri' ? 24 : 4), PAL.cream, 24); c.restore();
226
+ });
227
+ fatArrow(c, 1050, 225, 1120, 320, E.out(S(7.1, 7.35)), PAL.yellow, 18);
228
+ fatArrow(c, 1090, 450, 975, 470, E.out(S(7.9, 8.15)), PAL.yellow, 18);
229
+ fatArrow(c, 880, 400, 945, 240, E.out(S(9.0, 9.25)), PAL.yellow, 18);
230
+ }
231
+
232
+ // ---------- scene 3: progress ----------
233
+ if (scene === 3) {
234
+ const t0 = swap(BANDS[1]), prog = E.inOut(S(t0 + 0.2, 11.9)), base = 600, x0 = 110;
235
+ const ax = new Path2D(); ax.rect(x0 - 10, base, 700, 12); solid(c, ax, K, 0, 0);
236
+ for (let i = 0; i < 8; i++) {
237
+ const acc = 61 + 36 * (1 - Math.pow(1 - i / 7, 2)), bp = E.back(cl(prog * 8 - i, 0, 1)), h = (acc - 40) * 7 * bp; if (h <= 1) continue;
238
+ const p = new Path2D(); p.rect(x0 + 10 + i * 84, base - h, 62, h); solid(c, p, [PAL.magenta, PAL.blue, PAL.yellow, PAL.teal][i % 4], 7, 4);
239
+ c.save(); c.clip(p); if (i % 2) { c.fillStyle = 'rgba(21,21,21,0.5)'; for (let y = base - h; y < base; y += 16) c.fillRect(x0 + 10 + i * 84, y, 62, 6); } else { c.fillStyle = PAL.cream; for (let y = base - h + 8; y < base; y += 18) for (let x = 0; x < 3; x++) { c.beginPath(); c.arc(x0 + 22 + i * 84 + x * 19, y, 3.5, 0, 7); c.fill(); } } c.restore();
240
+ }
241
+ if (tq > t0 + 0.2) tag(c, 'TRAINING ROUNDS →', 440, 655, PAL.cream, 26);
242
+ // emphasis burst + confetti behind the number
243
+ const em = S(11.9, 12.1);
244
+ if (em > 0) { c.save(); c.translate(1010, 330); c.rotate(tq * 0.6); c.scale(E.back(em), E.back(em)); solid(c, burst(16, 150, 215), PAL.yellow, 12, 5); c.restore();
245
+ const rc = H.rng(5); for (let i = 0; i < 18; i++) { const a = rc.range(0, 7), d = 200 + rc.range(0, 120) * em; c.save(); c.translate(1010 + Math.cos(a) * d, 330 + Math.sin(a) * d); c.rotate(a + tq * 3); c.fillStyle = rc.pick([PAL.magenta, PAL.blue, PAL.teal, K]); c.beginPath(); c.moveTo(0, -12); c.lineTo(11, 8); c.lineTo(-11, 8); c.closePath(); c.fill(); c.restore(); } }
246
+ if (pop(t0 + 0.1, 1010, 330, 0.3)) { chunky(c, Math.round(H.lerp(61, 97, prog)) + '%', 1010, 330, 120, PAL.magenta, -10); c.restore(); }
247
+ if (tq > t0 + 0.3) tag(c, 'ACCURACY', 1010, 200, PAL.cream, 26, -0.05);
248
+ if (tq > t0 + 0.5) tag(c, '61% → 97%', 1010, 450, PAL.mint, 24, 0.04);
249
+ }
250
+
251
+ // ---------- scene 4: takeaway ----------
252
+ if (scene === 4) {
253
+ const t0 = swap(BANDS[2]);
254
+ if (pop(t0 + 0.05, 640, 360, 0.3)) {
255
+ c.translate(640, 360); c.rotate(-0.04 + Math.sin(tq * 2.4) * 0.01);
256
+ solid(c, bubble(1000, 360, [-300, 250]), PAL.yellow, 16, 6);
257
+ chunky(c, 'MORE EXAMPLES', 0, -70, 68, PAL.blue, -6);
258
+ if (tq >= t0 + 0.35) chunky(c, 'BETTER GUESSES!', 0, 80, 68, PAL.magenta, -6);
259
+ c.restore();
260
+ }
261
+ fatArrow(c, 640, 330, 640, 380, E.out(S(t0 + 0.2, t0 + 0.4)), PAL.teal, 16);
262
+ strokeOutlined(c, squigglePath(120, 640, 280, 16, 3, -0.08, tq * 3, S(t0 + 0.3, t0 + 0.8)), PAL.magenta, 12, 4, 6);
263
+ strokeOutlined(c, zigzagPath(900, 640, 260, 16, 9, -0.05, S(t0 + 0.4, t0 + 0.9)), PAL.teal, 11, 4, 6);
264
+ }
265
+
266
+ // ---------- corner sticker header (after the hook) ----------
267
+
268
+ // ---------- striped band swipe between scenes ----------
269
+ for (const b of BANDS) {
270
+ const u = S(b, b + 0.85); if (u <= 0 || u >= 1) continue;
271
+ const x = H.lerp(-2300, W + 900, u);
272
+ c.save(); c.translate(x, HH / 2); c.rotate(-0.35);
273
+ const band = new Path2D(); band.rect(0, -1400, 1700, 2800);
274
+ c.save(); c.translate(14, 14); c.fillStyle = K; c.fill(band); c.restore();
275
+ c.save(); c.clip(band); const cols = [PAL.magenta, PAL.yellow, PAL.blue, PAL.mint, PAL.red];
276
+ for (let i = 0; i < 20; i++) { c.fillStyle = cols[i % cols.length]; c.fillRect(i * 85, -1400, 86, 2800); c.fillStyle = K; for (let y = -1400; y < 1400; y += 40) { c.beginPath(); c.arc(i * 85 + 42, y + (i % 2) * 20, 5, 0, 7); c.fill(); } }
277
+ c.restore(); c.lineWidth = 6; c.strokeStyle = K; c.stroke(band); c.restore();
278
+ }
279
+ // header sticker stays on top
280
+ if (hp >= 1) { c.save(); c.translate(200, 80); c.rotate(-0.06); c.scale(0.42, 0.42); solid(c, bubble(820, 300, null), PAL.yellow, 16, 6); chunky(c, 'HOW DOES', 0, -50, 84, PAL.magenta); chunky(c, 'AI LEARN?', 0, 60, 84, PAL.blue); c.restore(); }
281
+ H.grain(ctx, W, HH, 0.05, 6 + Math.floor(t * 12), true);
282
+ };
283
+
284
+ registerStyle({
285
+ id: 'memphis',
286
+ name: 'Memphis Group',
287
+ category: 'Art & Design Movements',
288
+ description: 'Early-80s Memphis Milano maximalism: pastel grounds clashing with bold primaries, thick black outlines and hard offset shadows, squiggles, zigzags, dot grids, terrazzo chips and confetti triangles, all orbiting a chunky tilted chat-bubble headline.',
289
+ motion: 'Cut-out cel timing on twos: the mint wedge slides in, shapes pop on one by one with springy overshoot, squiggles and zigzags draw themselves, the chat bubble squash-and-stretches in, the words pop on the beat, confetti bursts out and the sticker slaps on; then everything bobs off-beat and the typing dots bounce.',
290
+ fonts: ['400 92px "Rubik Mono One"', '700 26px "Fredoka"'],
291
+ frameT: 4.1,
292
+ duration: 4.5,
293
+ readsPixels: true,
294
+ explainerDuration: 14.5,
295
+ explainerNote: 'Memphis cut-out animation on twos: examples hop into a funnel-topped totem computer, scenes change with a striped polka-dot band that swipes across, arrows are fat outlined shapes with hard shadows, counters are stickers that pop on each tick, and the key moments get a spinning starburst.',
296
+ explainer(ctx, W, HH, t) { explainMemphis(ctx, W, HH, t); },
297
+ // Sound: a playful 80s cut-out cartoon. Stickers and shapes land with rubbery pops, things hop on springy boings,
298
+ // the striped band swipes across as a fluttering zip, labels get bright synth stabs, the wrong guess is a sad
299
+ // "wah-wah" and the zigzag a buzzy zap, under a light synth-pop pulse. Times copied from explainMemphis(); it
300
+ // animates on twos at 12 fps, so q(x) is the first frame at which its quantised clock reaches x.
301
+ explainerSound(k) {
302
+ const D = 14.5, E = H.ease, cl = H.clamp;
303
+ const q = (x) => Math.ceil(x * 12 - 1e-6) / 12;
304
+ const land = (d, dur) => q(d + dur * 0.37); // back-eased pop(d, dur) first reaches full size at 37%
305
+ const pan = (px) => cl((px / 1280) * 2 - 1, -1, 1) * 0.7;
306
+ const when = (a, b, ease, u) => { for (let i = 0; i <= 400; i++) if (ease(i / 400) >= u - 1e-6) return q(a + ((b - a) * i) / 400); return q(b); };
307
+ const BANDS = [5.4, 9.8, 12.35], swap = (b) => b + 0.42, MX_ = 300; // MX_: the machine's x in scenes 1-2
308
+ // rubbery sticker pop (kept low)
309
+ const pop = (t, f, g, p, minor = true) => k.play('pop', t, { f, gain: g, pan: p, minor });
310
+ // springy boing: quick upward bend that sags back
311
+ const boing = (t, f, g, p, minor = true) => { k.tone(t, { f: [[0, f], [0.04, f * 2.4], [0.3, f * 1.3]], type: 'triangle', dur: 0.32, gain: 0.12 * g, a: 0.003, pan: p, minor }); k.tone(t, { f: [[0, f * 2], [0.05, f * 3.5], [0.2, f * 2.2]], dur: 0.2, gain: 0.03 * g, pan: p, minor }); };
312
+ // bright 80s synth stab (detuned saws through a closing filter)
313
+ const stab = (t, notes, g, p, minor) => notes.forEach((n, i) => { for (const det of [-10, 10])
314
+ k.tone(t, { f: n, type: 'sawtooth', detune: det, dur: 0.28, gain: 0.03 * g, a: 0.004, hold: 0.05, filter: 'lowpass', f2: [[0, 2600], [0.25, 700]], q: 2, pan: p + (i - 1) * 0.15, verb: 0.2, minor }); });
315
+ // the striped band: a fluttering zip as ~20 stripes rush past, left to right
316
+ const zip = (b) => {
317
+ const d = 0.85;
318
+ k.tone(b + 0.1, { f: [[0, 160], [d - 0.15, 520]], type: 'sawtooth', dur: d - 0.1, gain: 0.04, a: 0.25, filter: 'lowpass', f2: 1200, q: 3 });
319
+ for (let x = 0.08; x < d - 0.05; x += 1 / 28) { const e = Math.sin((x / d) * Math.PI);
320
+ k.noise(b + x, { dur: 0.025, filter: 'bandpass', f: 800 + e * 700, q: 1.5, gain: 0.16 * e, a: 0.002, pan: (x / d - 0.5) * 1.4 }); }
321
+ };
322
+ // a cartoon hand clap
323
+ const clap = (t, g, p) => [0, 0.012, 0.022].forEach((o) => k.noise(t + o, { dur: 0.05, filter: 'bandpass', f: 1300, q: 1.1, gain: 0.22 * g, a: 0.001, pan: p }));
324
+
325
+ k.music('pulse', 0, D, { bpm: 112, gain: 0.3, chords: [['C4', 'E4', 'G4', 'B4'], ['A3', 'C4', 'E4', 'G4'], ['F3', 'A3', 'C4', 'E4'], ['G3', 'B3', 'D4', 'F4']] });
326
+
327
+ // ---- hook: bubble pops up (back 0.1-0.45), HOW DOES (0.5), AI LEARN? + starburst (0.667), squiggle draws (0.3-0.9)
328
+ pop(land(0.1, 0.35), 360, 1.1, 0, false); boing(land(0.1, 0.35), 120, 0.8, 0, false);
329
+ stab(q(0.45), ['E4', 'G4', 'C5'], 0.9, -0.1, true);
330
+ stab(q(0.6), ['G4', 'C5', 'E5'], 1.1, 0.1, false); pop(q(0.6), 480, 0.8, pan(1120));
331
+ k.tone(0.32, { f: [[0, 140], [0.3, 220], [0.6, 170]], type: 'triangle', dur: 0.6, gain: 0.05, a: 0.1, filter: 'lowpass', f2: 900, pan: pan(200), minor: true }); // squiggle wiggles on
332
+ // bubble shrinks into the corner sticker (1.7-2.3): soft slide
333
+ k.noise(q(1.7), { dur: 0.6, color: 'pink', filter: 'bandpass', f: [[0, 700], [0.6, 350]], q: 0.8, gain: 0.07, a: 0.2, pan: -0.4, minor: true });
334
+
335
+ // ---- scene 1: DATA hops into the funnel
336
+ boing(land(2.0, 0.3), 90, 0.7, pan(MX_), false); k.play('thud', land(2.0, 0.3), { f: 120, gain: 0.2, pan: pan(MX_) });
337
+ pop(q(2.3 + 1e-3), 420, 0.6, pan(MX_)); // MODEL tag
338
+ const hops = []; for (let i = 0; 2.5 + i * 0.28 < 5.3; i++) hops.push(q(2.5 + i * 0.28));
339
+ hops.forEach((t, i) => boing(t, 150 + (i % 3) * 25, 0.55, pan(1180 - (i % 3) * 120)));
340
+ k.play('slap', when(2.7, 3.1, E.out, 0.95), { gain: 0.4, pan: pan(600), minor: true }); // fat arrow lands
341
+ pop(q(3.0 + 1e-3), 520, 0.8, pan(880)); // TRAINING DATA tag + counter sticker
342
+ // counter sticker swells on every other frame (6/s) while n = S(3.0,5.2)^3 * 1e6 ticks over
343
+ for (let f = Math.ceil(3.1 * 12); f / 12 < 5.2; f++) { const t = f / 12; if (f % 2 !== 1 || hops.some((h) => Math.abs(t - h) < 0.04)) continue;
344
+ pop(t, 640, 0.42, pan(960)); k.play('tick', t, { f: 2200, gain: 0.5, pan: pan(960), minor: true }); }
345
+ stab(q(5.2), ['C4', 'E4', 'G4', 'C5'], 1.2, pan(960)); pop(q(5.2), 300, 1, pan(960), false); // 1,000,000
346
+
347
+ // ---- the striped band swipes: 5.4, 9.8, 12.35
348
+ BANDS.forEach(zip);
349
+
350
+ // ---- scene 2: GUESS / CHECK / ADJUST (t0 = 5.82)
351
+ const t0 = swap(BANDS[0]);
352
+ pop(land(t0 + 0.1, 0.3), 380, 0.9, pan(560)); // new picture
353
+ [0, 1, 2].forEach((i) => pop(land(t0 + 0.2 + i * 0.12, 0.25), [440, 520, 600][i], 0.6, pan([1000, 1160, 900][i]))); // loop shapes
354
+ // the guess: DOG? bubble (back 6.7-6.95) with a questioning two-note blip
355
+ pop(land(6.7, 0.25), 340, 0.9, pan(600), false);
356
+ k.tone(land(6.7, 0.25) + 0.05, { f: 'D4', type: 'square', dur: 0.1, gain: 0.05, a: 0.003, hold: 0.06, filter: 'lowpass', f2: 1400, pan: pan(600) });
357
+ k.tone(land(6.7, 0.25) + 0.16, { f: 'A4', type: 'square', dur: 0.14, gain: 0.05, a: 0.003, hold: 0.08, filter: 'lowpass', f2: 1400, pan: pan(600) });
358
+ k.play('slap', when(7.1, 7.35, E.out, 0.95), { gain: 0.3, pan: pan(1090), minor: true });
359
+ // CHECK (7.417): starburst + cross + NOPE — a sad wah-wah
360
+ const ck = q(7.4);
361
+ pop(ck, 260, 1.1, pan(800), false); k.play('thud', ck, { f: 110, gain: 0.4, pan: pan(800) });
362
+ [['G3', 'F#3'], ['F#3', 'E3']].forEach(([a, b], i) => k.tone(ck + 0.05 + i * 0.24, { f: [[0, a], [0.2, b]], type: 'sawtooth', dur: i ? 0.45 : 0.22, gain: 0.12, a: 0.02, hold: 0.12, filter: 'lowpass', f2: [[0, 500], [0.1, 1300], [0.22, 500]], q: 3, pan: pan(800) }));
363
+ // ADJUST: the zigzag bolt zaps back to the knobs (7.8-8.2), ERROR! tag (8.25)
364
+ for (let x = 0; x < 0.4; x += 0.04) k.tone(q(7.8) + x, { f: 70 + (x * 37 % 1) * 60, type: 'sawtooth', dur: 0.035, gain: 0.07, a: 0.002, filter: 'bandpass', f2: 1500, q: 1.5, pan: pan(700 - x * 600) });
365
+ pop(q(8.2 + 1e-3), 420, 0.7, pan(520));
366
+ // knobs twist (inOut 8.3-9.0): ratchet clicks at least 90 ms apart
367
+ for (let i = 1, lt = 0; i <= 8; i++) { const t = when(8.3, 9.0, E.inOut, i / 8); if (t - lt < 0.09) continue; lt = t; k.play('click', t, { f: 1100, gain: 0.6, pan: pan(MX_), minor: true }); k.play('tock', t + 0.004, { f: 500 + i * 20, gain: 0.25, pan: pan(MX_), minor: true }); }
368
+ k.play('slap', when(9.0, 9.25, E.out, 0.95), { gain: 0.3, pan: pan(910), minor: true });
369
+ // the correction: CAT! bubble (9.417), teal starburst + tick (9.667) — a bouncy major arpeggio
370
+ pop(land(9.3, 0.25), 420, 0.9, pan(600));
371
+ ['C4', 'E4', 'G4', 'C5'].forEach((n, i) => k.tone(q(9.6) + i * 0.06, { f: n, type: 'triangle', dur: 0.35, gain: 0.13, a: 0.003, pan: pan(790), verb: 0.2 }));
372
+ pop(q(9.6), 500, 0.9, pan(790), false);
373
+
374
+ // ---- scene 3: PROGRESS (t0 = 10.22): number pops (10.5), bars spring up one by one as prog = inOut(S(10.42,11.9)) passes i/8
375
+ const t3 = swap(BANDS[1]);
376
+ pop(land(t3 + 0.1, 0.3), 330, 0.9, pan(1010), false);
377
+ const bars = []; for (let i = 0; i < 8; i++) { const t = when(t3 + 0.2, 11.9, E.inOut, i / 8 + 0.02); if (bars.length && t - bars[bars.length - 1] < 0.09) continue; bars.push(t); boing(t, 110 + i * 14, 0.6, pan(150 + i * 84)); }
378
+ for (let f = Math.ceil(10.5 * 12), last = 61; f / 12 < 11.9; f++) { const t = f / 12, v = Math.round(H.lerp(61, 97, E.inOut(cl((t - t3 - 0.2) / (11.9 - t3 - 0.2), 0, 1))));
379
+ if (v !== last && !bars.some((b) => Math.abs(t - b) < 0.04)) { pop(t, 680, 0.38, pan(1010)); k.play('tick', t, { f: 2200, gain: 0.5, pan: pan(1010), minor: true }); last = v; } }
380
+ // 97%: yellow starburst springs out with confetti (12.0) — the biggest hit
381
+ const big = land(11.9, 0.2);
382
+ k.play('impact', big, { gain: 1.7, pan: pan(1010) }); k.play('thud', big, { f: 70, gain: 0.6 });
383
+ stab(big, ['C4', 'E4', 'G4', 'C5'], 1.6, pan(1010));
384
+ clap(big, 1, pan(1010)); boing(big, 80, 1.2, pan(1010), false);
385
+ for (let i = 0; i < 6; i++) pop(big + 0.3 + i * 0.08, 280 + (i * 97) % 300, 0.6, (i % 2 ? 0.4 : -0.4) + pan(1010) * 0.5); // confetti flies out
386
+
387
+ // ---- scene 4: TAKEAWAY (t0 = 12.77): bubble pops (13.0), arrow, BETTER GUESSES! (13.167), squiggle + zigzag draw on
388
+ const t4 = swap(BANDS[2]);
389
+ pop(land(t4 + 0.05, 0.3), 340, 1.0, 0, false); boing(land(t4 + 0.05, 0.3), 110, 0.7, 0);
390
+ k.tone(q(t4 + 0.3), { f: [[0, 150], [0.5, 230]], type: 'triangle', dur: 0.5, gain: 0.04, a: 0.1, filter: 'lowpass', f2: 900, pan: -0.5, minor: true });
391
+ stab(q(t4 + 0.35), ['F4', 'A4', 'C5'], 0.8, 0.1, true);
392
+ ['C4', 'G4', 'C5', 'E5'].forEach((n, i) => k.tone(q(t4 + 0.35) + 0.25 + i * 0.07, { f: n, type: 'triangle', dur: 0.8, gain: 0.12 - i * 0.015, a: 0.003, pan: (i - 1.5) * 0.25, verb: 0.3 })); // resolves
393
+ clap(q(t4 + 0.35) + 0.25, 0.6, 0);
394
+ },
395
+ draw(ctx, W, HH, t) {
396
+ const c = ctx;
397
+ // cel-style timing: all motion is held for two frames (12 fps steps) like 80s cut-out animation
398
+ const tq = Math.floor(t * 12) / 12;
399
+ const bob = (ph, a = 6) => Math.sin(tq * 2.1 + ph) * a;
400
+ const P = (d, dur = 0.5) => H.clamp((tq - d) / dur, 0, 1);
401
+ const pop = (d, x, y, dur = 0.25) => { const s = H.ease.back(P(d, dur)); if (s <= 0) return false; c.save(); c.translate(x, y); c.scale(s, s); c.translate(-x, -y); return true; };
402
+
403
+ // ---------- ground: pastel split (mint wedge slides in) ----------
404
+ c.fillStyle = PAL.pink; c.fillRect(0, 0, W, HH);
405
+ { const off = (1 - H.ease.out(P(0, 0.33))) * 760;
406
+ c.fillStyle = PAL.mint; c.beginPath(); c.moveTo(820 + off, 0); c.lineTo(W + off, 0); c.lineTo(W + off, HH); c.lineTo(560 + off, HH); c.closePath(); c.fill(); }
407
+ // fine black dash texture on the pink (classic Memphis "bacterio"-lite), sprinkled on
408
+ const rb = H.rng(3), nb = Math.floor(260 * P(0.15, 0.4));
409
+ c.fillStyle = 'rgba(21,21,21,0.55)';
410
+ for (let i = 0; i < 260; i++) {
411
+ const x = rb.range(0, 760), y = rb.range(0, HH); const a = rb.range(0, Math.PI), l = rb.range(3, 7);
412
+ if (i >= nb) continue;
413
+ c.save(); c.translate(x, y); c.rotate(a); c.beginPath(); c.ellipse(0, 0, l, 1.6, 0, 0, 7); c.fill(); c.restore();
414
+ }
415
+
416
+ // ---------- background shapes, popping in one by one ----------
417
+ // terrazzo semicircle dropping from the top-left
418
+ { const dy = -(1 - H.ease.back(P(0.25, 0.3))) * 230;
419
+ const semi = new Path2D(); semi.arc(210, -10 + bob(0.3, 4) + dy, 190, 0, Math.PI); semi.closePath();
420
+ c.save(); c.translate(10, 10); c.fillStyle = K; c.fill(semi); c.restore();
421
+ terrazzo(c, semi, 11); c.lineWidth = 5; c.strokeStyle = K; c.stroke(semi); }
422
+
423
+ // dot grid panel (top right)
424
+ if (pop(0.42, 1065, 139)) {
425
+ c.translate(0, bob(1.2, 3));
426
+ const dg = new Path2D(); dg.rect(930, 54, 270, 170);
427
+ solid(c, dg, PAL.butter, 10);
428
+ c.fillStyle = K; for (let y = 70; y < 220; y += 18) for (let x = 946; x < 1196; x += 18) { c.beginPath(); c.arc(x, y, 3.4, 0, 7); c.fill(); }
429
+ c.restore();
430
+ }
431
+
432
+ // big blue circle bottom-left with stripes inside half
433
+ if (pop(0.58, 190, 560)) {
434
+ const bc = new Path2D(); bc.arc(190, 560 + bob(2.0, 5), 122, 0, Math.PI * 2);
435
+ solid(c, bc, PAL.blue, 12);
436
+ c.save(); c.clip(bc); c.fillStyle = PAL.cream; for (let x = 60; x < 330; x += 22) c.fillRect(x, 560, 11, 200); c.restore();
437
+ c.lineWidth = 5; c.strokeStyle = K; c.stroke(bc);
438
+ c.restore();
439
+ }
440
+
441
+ // teal triangle bottom-right
442
+ if (pop(0.72, 1090, 560)) {
443
+ c.translate(1090, 560); c.rotate(-0.2 + Math.sin(tq * 1.3) * 0.05);
444
+ const tri = new Path2D(); tri.moveTo(0, -120); tri.lineTo(115, 85); tri.lineTo(-115, 85); tri.closePath();
445
+ solid(c, tri, PAL.teal, 12);
446
+ c.save(); c.clip(tri); c.fillStyle = K; for (let k = -6; k < 8; k++) { c.beginPath(); c.arc(k * 26, 40, 4, 0, 7); c.fill(); c.beginPath(); c.arc(k * 26 + 13, 64, 4, 0, 7); c.fill(); } c.restore();
447
+ c.restore();
448
+ }
449
+
450
+ // lilac slab tilted behind bubble (unfolds sideways)
451
+ { const sx = H.ease.back(P(0.88, 0.25));
452
+ if (sx > 0) {
453
+ c.save(); c.translate(660, 360); c.rotate(0.09); c.scale(sx, 1);
454
+ const slab = new Path2D(); slab.rect(-360, -150, 700, 300);
455
+ solid(c, slab, PAL.lilac, 0);
456
+ c.save(); c.clip(slab); c.strokeStyle = 'rgba(21,21,21,0.5)'; c.lineWidth = 2;
457
+ for (let x = -360; x < 360; x += 30) { c.beginPath(); c.moveTo(x, -150); c.lineTo(x, 150); c.stroke(); }
458
+ for (let y = -150; y < 150; y += 30) { c.beginPath(); c.moveTo(-360, y); c.lineTo(360, y); c.stroke(); }
459
+ c.restore(); c.lineWidth = 5; c.strokeStyle = K; c.stroke(slab);
460
+ c.restore();
461
+ } }
462
+
463
+ // squiggles + zigzags draw themselves on
464
+ const dr = (d) => H.ease.inOut(P(d, 0.4));
465
+ if (dr(1.0) > 0) strokeOutlined(c, squigglePath(400, 92, 300, 18, 3.5, -0.08, tq * 3, dr(1.0)), PAL.yellow, 14, 4, 7);
466
+ if (dr(1.1) > 0) strokeOutlined(c, zigzagPath(940, 290, 230, 18, 9, 0.12, dr(1.1)), PAL.magenta, 13, 4, 7);
467
+ c.lineCap = 'round'; c.strokeStyle = K; c.lineWidth = 7;
468
+ if (dr(1.2) > 0) c.stroke(squigglePath(610, 668, 200, 12, 4, -0.08, -tq * 3, dr(1.2)));
469
+ if (dr(1.05) > 0) c.stroke(squigglePath(70, 250, 140, 12, 2.5, 1.35, tq * 2.5, dr(1.05)));
470
+ if (dr(1.25) > 0) strokeOutlined(c, zigzagPath(330, 640, 160, 14, 7, -0.05, dr(1.25)), PAL.blue, 10, 3.5, 6);
471
+
472
+ // confetti: bursts out of the bubble, then tumbles in place
473
+ const rc = H.rng(77);
474
+ const keep = (x, y) => !(x > 250 && x < 1060 && y > 170 && y < 560);
475
+ const cols = [PAL.magenta, PAL.blue, PAL.yellow, PAL.teal, PAL.red, K];
476
+ let placed = 0;
477
+ for (let i = 0; i < 200 && placed < 34; i++) {
478
+ const x = rc.range(40, W - 40), y = rc.range(30, HH - 30); if (!keep(x, y)) continue;
479
+ if (Math.hypot(x - 190, y - 560) < 150 || (x > 910 && x < 1220 && y > 40 && y < 240) || Math.hypot(x - 210, y) < 210 || Math.hypot(x - 1090, y - 570) < 150) continue;
480
+ placed++;
481
+ const s = rc.range(10, 18), kind = rc.int(0, 3), col = rc.pick(cols), rot = rc.range(0, 7) + tq * rc.range(-1.5, 1.5), dl = rc.range(0, 0.15);
482
+ const fp = H.ease.out(P(1.4 + dl, 0.4)); if (fp <= 0) continue;
483
+ const px = H.lerp(640, x, fp), py = H.lerp(350, y, fp) - Math.sin(fp * Math.PI) * 60;
484
+ c.save(); c.translate(px, py + bob(i, 3)); c.rotate(rot + (1 - fp) * 6);
485
+ const p = new Path2D();
486
+ if (kind <= 1) { p.moveTo(0, -s); p.lineTo(s * 0.9, s * 0.6); p.lineTo(-s * 0.9, s * 0.6); p.closePath(); c.fillStyle = col; c.fill(p); c.lineWidth = 3; c.strokeStyle = K; c.stroke(p); }
487
+ else if (kind === 2) { c.fillStyle = col; c.fillRect(-s * 0.9, -3.5, s * 1.8, 7); }
488
+ else { c.beginPath(); c.arc(0, 0, s * 0.45, 0, 7); c.fillStyle = col; c.fill(); c.lineWidth = 3; c.strokeStyle = K; c.stroke(); }
489
+ c.restore();
490
+ }
491
+
492
+ // ---------- hero: chunky chat bubble headline (squash & stretch pop) ----------
493
+ const bp = P(1.3, 0.4);
494
+ if (bp > 0) {
495
+ const e = H.ease.back(bp), breathe = bp >= 1 ? Math.sin(tq * 2.4) * 0.012 : 0;
496
+ const sxB = bp < 1 ? e * (1 + 0.25 * Math.sin(bp * Math.PI)) : 1 + breathe, syB = bp < 1 ? e * (1 - 0.18 * Math.sin(bp * Math.PI)) : 1 - breathe;
497
+ c.save(); c.translate(640, 350); c.rotate(-0.06); c.scale(sxB, syB);
498
+ const bw = 640, bh = 250, rr = 46;
499
+ const bub = new Path2D();
500
+ bub.moveTo(-bw / 2 + rr, -bh / 2); bub.lineTo(bw / 2 - rr, -bh / 2); bub.quadraticCurveTo(bw / 2, -bh / 2, bw / 2, -bh / 2 + rr);
501
+ bub.lineTo(bw / 2, bh / 2 - rr); bub.quadraticCurveTo(bw / 2, bh / 2, bw / 2 - rr, bh / 2);
502
+ bub.lineTo(-150, bh / 2); bub.lineTo(-230, bh / 2 + 80); bub.lineTo(-215, bh / 2);
503
+ bub.lineTo(-bw / 2 + rr, bh / 2); bub.quadraticCurveTo(-bw / 2, bh / 2, -bw / 2, bh / 2 - rr);
504
+ bub.lineTo(-bw / 2, -bh / 2 + rr); bub.quadraticCurveTo(-bw / 2, -bh / 2, -bw / 2 + rr, -bh / 2); bub.closePath();
505
+ solid(c, bub, PAL.yellow, 16, 6);
506
+ // headline: chunky with hard shadow, each word pops on its own beat
507
+ c.textAlign = 'center'; c.textBaseline = 'alphabetic'; c.font = '400 92px "Rubik Mono One"'; c.letterSpacing = '-7px';
508
+ const line = (txt, a, b, d, e2) => {
509
+ let x = 0, y = a, col = b; if (e2) { x = a; y = b; col = d; }
510
+ c.lineJoin = 'round';
511
+ c.fillStyle = K; c.fillText(txt, x + 7, y + 7);
512
+ c.lineWidth = 8; c.strokeStyle = K; c.strokeText(txt, x, y);
513
+ c.fillStyle = col; c.fillText(txt, x, y);
514
+ };
515
+ if (pop(1.6, 0, -40, 0.2)) { line('HELLO', -12, PAL.magenta); c.restore(); }
516
+ { const wH = c.measureText('HUMAN').width, wX = c.measureText('!').width * 0.45, x0 = -(wH + wX) / 2;
517
+ if (pop(1.75, 0, 60, 0.2)) { c.textAlign = 'left'; line('HUMAN', x0, 88, PAL.blue, true); c.restore(); }
518
+ const bx = x0 + wH - c.measureText('!').width * 0.32;
519
+ if (pop(1.92, bx + 30, 50, 0.2)) { c.textAlign = 'left'; c.translate(bx, 0); c.rotate(0.12); line('!', 0, 88, PAL.magenta, true); c.restore(); }
520
+ c.textAlign = 'center'; }
521
+ c.letterSpacing = '0px';
522
+ // typing dots badge
523
+ if (pop(2.05, 250, -118, 0.2)) {
524
+ c.translate(250, -118); c.rotate(0.1);
525
+ const bd = new Path2D(); bd.ellipse(0, 0, 62, 30, 0, 0, Math.PI * 2);
526
+ solid(c, bd, PAL.cream, 6, 4);
527
+ for (let k = 0; k < 3; k++) { const up = Math.max(0, Math.sin(tq * 6 - k * 0.9)) * 6; c.fillStyle = [PAL.magenta, PAL.teal, PAL.blue][k]; c.beginPath(); c.arc(-24 + k * 24, -up, 8, 0, 7); c.fill(); c.lineWidth = 3; c.strokeStyle = K; c.stroke(); }
528
+ c.restore();
529
+ }
530
+ c.restore();
531
+ }
532
+
533
+ // small caption sticker slapped on last
534
+ { const sp = P(2.2, 0.2);
535
+ if (sp > 0) {
536
+ const k = H.ease.out(sp);
537
+ c.save(); c.translate(860, 548); c.rotate(-0.04 - (1 - k) * 0.35); c.scale(1.35 - 0.35 * k, 1.35 - 0.35 * k);
538
+ const st = new Path2D(); st.rect(-120, -24, 240, 48);
539
+ solid(c, st, PAL.cream, 7 * k, 4);
540
+ c.fillStyle = K; c.font = '700 26px "Fredoka"'; c.textAlign = 'center'; c.textBaseline = 'middle'; c.fillText('your new AI pal', 0, 1);
541
+ c.restore();
542
+ } }
543
+
544
+ // ---------- print finish ----------
545
+ H.grain(ctx, W, HH, 0.05, 6 + Math.floor(t * 12), true);
546
+ },
547
+ });
548
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "id": 67,
3
+ "name": "Memphis Group",
4
+ "nameZh": "孟菲斯设计",
5
+ "family": "Art & Design Movements",
6
+ "familyZh": "艺术与设计流派",
7
+ "description": "Early-80s Memphis Milano maximalism: pastel grounds clashing with bold primaries, thick black outlines and hard offset shadows, squiggles, zigzags, dot grids, terrazzo chips and confetti triangles, all orbiting a chunky tilted chat-bubble headline.",
8
+ "motionNotes": "Motion: Cut-out cel timing on twos: the mint wedge slides in, shapes pop on one by one with springy overshoot, squiggles and zigzags draw themselves, the chat bubble squash-and-stretches in, the words pop on the beat, confetti bursts out and the sticker slaps on; then everything bobs off-beat and the typing dots bounce.",
9
+ "explainerNotes": "Explainer: Memphis cut-out animation on twos: examples hop into a funnel-topped totem computer, scenes change with a striped polka-dot band that swipes across, arrows are fat outlined shapes with hard shadows, counters are stickers that pop on each tick, and the key moments get a spinning starburst.",
10
+ "code": "code.js",
11
+ "registeredAs": "memphis",
12
+ "source": "https://www.futurepedia.io/resources/ai-style-atlas/view"
13
+ }