@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.
- package/MANUAL.md +94 -84
- package/package.json +1 -1
- package/product.json +2 -1
- package/skills/aicut/SKILL.md +4 -4
- package/skills/aicut/references/commands.md +15 -15
- package/skills/aicut/references/film-format.md +1 -1
- package/skills/aicut/references/recipes.md +4 -4
- package/skills/aicut/references/troubleshooting.md +2 -2
- package/skills/aicut-motion/SKILL.md +75 -9
- package/skills/aicut-motion/THIRD_PARTY_NOTICES.md +14 -0
- package/skills/aicut-motion/assets/atlas/lib/harness.js +116 -0
- package/skills/aicut-motion/assets/atlas/lib/sound.js +274 -0
- package/skills/aicut-motion/assets/atlas/styles/001-flat-vector-science/code.js +937 -0
- package/skills/aicut-motion/assets/atlas/styles/001-flat-vector-science/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/001-flat-vector-science/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/002-watercolor-wash/code.js +909 -0
- package/skills/aicut-motion/assets/atlas/styles/002-watercolor-wash/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/002-watercolor-wash/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/003-shadow-puppet-theatre/code.js +881 -0
- package/skills/aicut-motion/assets/atlas/styles/003-shadow-puppet-theatre/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/003-shadow-puppet-theatre/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/004-whiteboard-explainer/code.js +897 -0
- package/skills/aicut-motion/assets/atlas/styles/004-whiteboard-explainer/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/004-whiteboard-explainer/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/005-psychedelic-poster/code.js +814 -0
- package/skills/aicut-motion/assets/atlas/styles/005-psychedelic-poster/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/005-psychedelic-poster/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/006-tech-glow-explainer/code.js +990 -0
- package/skills/aicut-motion/assets/atlas/styles/006-tech-glow-explainer/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/006-tech-glow-explainer/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/007-papercraft-models/code.js +994 -0
- package/skills/aicut-motion/assets/atlas/styles/007-papercraft-models/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/007-papercraft-models/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/008-1940s-film-noir/code.js +792 -0
- package/skills/aicut-motion/assets/atlas/styles/008-1940s-film-noir/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/008-1940s-film-noir/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/009-manim-style-math/code.js +840 -0
- package/skills/aicut-motion/assets/atlas/styles/009-manim-style-math/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/009-manim-style-math/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/010-illuminated-manuscript/code.js +1126 -0
- package/skills/aicut-motion/assets/atlas/styles/010-illuminated-manuscript/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/010-illuminated-manuscript/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/011-editorial-essay-collage/code.js +854 -0
- package/skills/aicut-motion/assets/atlas/styles/011-editorial-essay-collage/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/011-editorial-essay-collage/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/012-bioluminescent-deep-sea/code.js +1124 -0
- package/skills/aicut-motion/assets/atlas/styles/012-bioluminescent-deep-sea/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/012-bioluminescent-deep-sea/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/013-product-launch-reveal/code.js +728 -0
- package/skills/aicut-motion/assets/atlas/styles/013-product-launch-reveal/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/013-product-launch-reveal/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/014-halftone-pop-panel/code.js +664 -0
- package/skills/aicut-motion/assets/atlas/styles/014-halftone-pop-panel/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/014-halftone-pop-panel/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/015-isometric-pastel/code.js +991 -0
- package/skills/aicut-motion/assets/atlas/styles/015-isometric-pastel/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/015-isometric-pastel/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/016-oscilloscope-vector-art/code.js +801 -0
- package/skills/aicut-motion/assets/atlas/styles/016-oscilloscope-vector-art/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/016-oscilloscope-vector-art/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/017-risograph-zine/code.js +692 -0
- package/skills/aicut-motion/assets/atlas/styles/017-risograph-zine/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/017-risograph-zine/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/018-claymation-set/code.js +756 -0
- package/skills/aicut-motion/assets/atlas/styles/018-claymation-set/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/018-claymation-set/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/019-neon-sign-at-night/code.js +922 -0
- package/skills/aicut-motion/assets/atlas/styles/019-neon-sign-at-night/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/019-neon-sign-at-night/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/020-kawaii-anime/code.js +852 -0
- package/skills/aicut-motion/assets/atlas/styles/020-kawaii-anime/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/020-kawaii-anime/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/021-ukiyo-e-woodblock/code.js +724 -0
- package/skills/aicut-motion/assets/atlas/styles/021-ukiyo-e-woodblock/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/021-ukiyo-e-woodblock/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/022-16-bit-pixel-odyssey/code.js +793 -0
- package/skills/aicut-motion/assets/atlas/styles/022-16-bit-pixel-odyssey/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/022-16-bit-pixel-odyssey/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/023-chalkboard-lesson/code.js +846 -0
- package/skills/aicut-motion/assets/atlas/styles/023-chalkboard-lesson/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/023-chalkboard-lesson/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/024-cut-paper-diorama/code.js +1008 -0
- package/skills/aicut-motion/assets/atlas/styles/024-cut-paper-diorama/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/024-cut-paper-diorama/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/025-cathedral-glass/code.js +680 -0
- package/skills/aicut-motion/assets/atlas/styles/025-cathedral-glass/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/025-cathedral-glass/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/026-editorial-chart/code.js +633 -0
- package/skills/aicut-motion/assets/atlas/styles/026-editorial-chart/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/026-editorial-chart/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/027-synthwave-outrun/code.js +757 -0
- package/skills/aicut-motion/assets/atlas/styles/027-synthwave-outrun/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/027-synthwave-outrun/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/028-origami-studio/code.js +828 -0
- package/skills/aicut-motion/assets/atlas/styles/028-origami-studio/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/028-origami-studio/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/029-linocut-relief-print/code.js +697 -0
- package/skills/aicut-motion/assets/atlas/styles/029-linocut-relief-print/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/029-linocut-relief-print/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/030-holographic-foil-card/code.js +687 -0
- package/skills/aicut-motion/assets/atlas/styles/030-holographic-foil-card/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/030-holographic-foil-card/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/031-voxel-diorama/code.js +727 -0
- package/skills/aicut-motion/assets/atlas/styles/031-voxel-diorama/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/031-voxel-diorama/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/032-sumi-e-ink-wash/code.js +903 -0
- package/skills/aicut-motion/assets/atlas/styles/032-sumi-e-ink-wash/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/032-sumi-e-ink-wash/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/033-etch-a-sketch-toy/code.js +662 -0
- package/skills/aicut-motion/assets/atlas/styles/033-etch-a-sketch-toy/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/033-etch-a-sketch-toy/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/034-cosmic-star-chart/code.js +951 -0
- package/skills/aicut-motion/assets/atlas/styles/034-cosmic-star-chart/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/034-cosmic-star-chart/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/035-punk-zine-collage/code.js +759 -0
- package/skills/aicut-motion/assets/atlas/styles/035-punk-zine-collage/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/035-punk-zine-collage/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/036-thermal-camera/code.js +738 -0
- package/skills/aicut-motion/assets/atlas/styles/036-thermal-camera/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/036-thermal-camera/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/037-engineering-blueprint/code.js +793 -0
- package/skills/aicut-motion/assets/atlas/styles/037-engineering-blueprint/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/037-engineering-blueprint/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/038-impasto-night/code.js +673 -0
- package/skills/aicut-motion/assets/atlas/styles/038-impasto-night/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/038-impasto-night/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/039-win95-desktop/code.js +907 -0
- package/skills/aicut-motion/assets/atlas/styles/039-win95-desktop/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/039-win95-desktop/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/040-low-poly-faceted/code.js +833 -0
- package/skills/aicut-motion/assets/atlas/styles/040-low-poly-faceted/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/040-low-poly-faceted/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/041-manga-page/code.js +845 -0
- package/skills/aicut-motion/assets/atlas/styles/041-manga-page/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/041-manga-page/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/042-wood-type-letterpress/code.js +496 -0
- package/skills/aicut-motion/assets/atlas/styles/042-wood-type-letterpress/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/042-wood-type-letterpress/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/043-light-painting/code.js +635 -0
- package/skills/aicut-motion/assets/atlas/styles/043-light-painting/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/043-light-painting/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/044-felt-patchwork/code.js +799 -0
- package/skills/aicut-motion/assets/atlas/styles/044-felt-patchwork/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/044-felt-patchwork/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/045-phosphor-terminal/code.js +547 -0
- package/skills/aicut-motion/assets/atlas/styles/045-phosphor-terminal/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/045-phosphor-terminal/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/046-glassmorphism-ui/code.js +592 -0
- package/skills/aicut-motion/assets/atlas/styles/046-glassmorphism-ui/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/046-glassmorphism-ui/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/047-tarot-card/code.js +768 -0
- package/skills/aicut-motion/assets/atlas/styles/047-tarot-card/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/047-tarot-card/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/048-transit-map/code.js +666 -0
- package/skills/aicut-motion/assets/atlas/styles/048-transit-map/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/048-transit-map/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/049-gouache-travel-poster/code.js +559 -0
- package/skills/aicut-motion/assets/atlas/styles/049-gouache-travel-poster/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/049-gouache-travel-poster/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/050-napkin-sketch/code.js +943 -0
- package/skills/aicut-motion/assets/atlas/styles/050-napkin-sketch/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/050-napkin-sketch/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/051-art-deco-foil/code.js +606 -0
- package/skills/aicut-motion/assets/atlas/styles/051-art-deco-foil/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/051-art-deco-foil/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/052-radiograph-on-lightbox/code.js +730 -0
- package/skills/aicut-motion/assets/atlas/styles/052-radiograph-on-lightbox/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/052-radiograph-on-lightbox/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/053-vaporwave/code.js +782 -0
- package/skills/aicut-motion/assets/atlas/styles/053-vaporwave/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/053-vaporwave/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/054-ebru-paper-marbling/code.js +504 -0
- package/skills/aicut-motion/assets/atlas/styles/054-ebru-paper-marbling/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/054-ebru-paper-marbling/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/055-isotype-pictograms/code.js +517 -0
- package/skills/aicut-motion/assets/atlas/styles/055-isotype-pictograms/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/055-isotype-pictograms/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/056-soft-3d-clay/code.js +713 -0
- package/skills/aicut-motion/assets/atlas/styles/056-soft-3d-clay/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/056-soft-3d-clay/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/057-cross-stitch-sampler/code.js +717 -0
- package/skills/aicut-motion/assets/atlas/styles/057-cross-stitch-sampler/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/057-cross-stitch-sampler/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/058-constructivist-propaganda/code.js +540 -0
- package/skills/aicut-motion/assets/atlas/styles/058-constructivist-propaganda/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/058-constructivist-propaganda/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/059-pocket-monochrome/code.js +524 -0
- package/skills/aicut-motion/assets/atlas/styles/059-pocket-monochrome/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/059-pocket-monochrome/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/060-botanical-plate/code.js +934 -0
- package/skills/aicut-motion/assets/atlas/styles/060-botanical-plate/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/060-botanical-plate/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/061-kinetic-type/code.js +690 -0
- package/skills/aicut-motion/assets/atlas/styles/061-kinetic-type/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/061-kinetic-type/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/062-byzantine-mosaic/code.js +612 -0
- package/skills/aicut-motion/assets/atlas/styles/062-byzantine-mosaic/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/062-byzantine-mosaic/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/063-y2k-liquid-chrome/code.js +666 -0
- package/skills/aicut-motion/assets/atlas/styles/063-y2k-liquid-chrome/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/063-y2k-liquid-chrome/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/064-sticky-note-wall/code.js +651 -0
- package/skills/aicut-motion/assets/atlas/styles/064-sticky-note-wall/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/064-sticky-note-wall/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/065-vintage-newsprint/code.js +656 -0
- package/skills/aicut-motion/assets/atlas/styles/065-vintage-newsprint/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/065-vintage-newsprint/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/066-hidden-line-wireframe/code.js +672 -0
- package/skills/aicut-motion/assets/atlas/styles/066-hidden-line-wireframe/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/066-hidden-line-wireframe/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/067-memphis-group/code.js +548 -0
- package/skills/aicut-motion/assets/atlas/styles/067-memphis-group/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/067-memphis-group/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/068-ballpoint-notebook/code.js +989 -0
- package/skills/aicut-motion/assets/atlas/styles/068-ballpoint-notebook/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/068-ballpoint-notebook/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/069-op-art-sphere/code.js +440 -0
- package/skills/aicut-motion/assets/atlas/styles/069-op-art-sphere/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/069-op-art-sphere/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/070-topographic-survey/code.js +895 -0
- package/skills/aicut-motion/assets/atlas/styles/070-topographic-survey/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/070-topographic-survey/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/071-pointillist-afternoon/code.js +563 -0
- package/skills/aicut-motion/assets/atlas/styles/071-pointillist-afternoon/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/071-pointillist-afternoon/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/072-vector-arcade-1980/code.js +627 -0
- package/skills/aicut-motion/assets/atlas/styles/072-vector-arcade-1980/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/072-vector-arcade-1980/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/073-patent-drawing/code.js +1096 -0
- package/skills/aicut-motion/assets/atlas/styles/073-patent-drawing/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/073-patent-drawing/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/074-bauhaus-poster/code.js +595 -0
- package/skills/aicut-motion/assets/atlas/styles/074-bauhaus-poster/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/074-bauhaus-poster/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/075-bitmap-paint-doodle/code.js +665 -0
- package/skills/aicut-motion/assets/atlas/styles/075-bitmap-paint-doodle/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/075-bitmap-paint-doodle/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/076-nail-thread-string-art/code.js +645 -0
- package/skills/aicut-motion/assets/atlas/styles/076-nail-thread-string-art/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/076-nail-thread-string-art/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/077-ridgeline/code.js +436 -0
- package/skills/aicut-motion/assets/atlas/styles/077-ridgeline/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/077-ridgeline/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/078-sketchbook-graphite/code.js +1237 -0
- package/skills/aicut-motion/assets/atlas/styles/078-sketchbook-graphite/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/078-sketchbook-graphite/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/079-teletext-page/code.js +622 -0
- package/skills/aicut-motion/assets/atlas/styles/079-teletext-page/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/079-teletext-page/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/080-silkscreen-grid/code.js +524 -0
- package/skills/aicut-motion/assets/atlas/styles/080-silkscreen-grid/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/080-silkscreen-grid/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/081-guilloch-security-print/code.js +689 -0
- package/skills/aicut-motion/assets/atlas/styles/081-guilloch-security-print/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/081-guilloch-security-print/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/082-ascii-demoscene/code.js +574 -0
- package/skills/aicut-motion/assets/atlas/styles/082-ascii-demoscene/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/082-ascii-demoscene/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/083-international-typographic-style/code.js +469 -0
- package/skills/aicut-motion/assets/atlas/styles/083-international-typographic-style/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/083-international-typographic-style/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/084-flow-field/code.js +531 -0
- package/skills/aicut-motion/assets/atlas/styles/084-flow-field/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/084-flow-field/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/085-macpaint-1984/code.js +675 -0
- package/skills/aicut-motion/assets/atlas/styles/085-macpaint-1984/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/085-macpaint-1984/style.json +13 -0
- package/skills/aicut-motion/assets/atlas/styles/086-multi-scale-truchet/code.js +609 -0
- package/skills/aicut-motion/assets/atlas/styles/086-multi-scale-truchet/poster.jpg +0 -0
- package/skills/aicut-motion/assets/atlas/styles/086-multi-scale-truchet/style.json +13 -0
- package/skills/aicut-motion/references/design-systems/README.md +1 -1
- package/skills/aicut-motion/references/motion-delivery.md +55 -0
- package/skills/aicut-motion/references/pages.md +1 -1
- package/skills/aicut-motion/references/style-index.json +690 -0
- package/skills/aicut-motion/references/style-research.md +73 -0
- package/skills/aicut-motion/references/style-selection.md +71 -0
- package/skills/aicut-motion/scripts/atlas-viewer.html +195 -0
- package/skills/aicut-motion/scripts/atlas.mjs +109 -0
- package/studio/client.mjs +3 -3
- package/studio/server/fetch-github.mjs +14 -3
- package/studio/server/server.mjs +71 -6
- package/studio/server/skill-summaries.mjs +60 -0
- package/studio/server/skills.mjs +121 -7
- package/studio/server/styles-store.mjs +235 -0
- package/studio/server/template-posters.mjs +2 -2
- package/studio/server/templates-page.mjs +93 -93
- package/studio/server/templates.mjs +32 -7
- package/studio/ui/dist/assets/ExportCenter-DasulhAv.js +1 -0
- package/studio/ui/dist/assets/SettingsModal-BZw0Hz2_.js +2 -0
- package/studio/ui/dist/assets/apple-touch-icon-ClxQ7j-O.png +0 -0
- package/studio/ui/dist/assets/es-C8XPZARI.js +1 -0
- package/studio/ui/dist/assets/favicon-Blwx8Trs.png +0 -0
- package/studio/ui/dist/assets/index-BjJVmBzB.js +1623 -0
- package/studio/ui/dist/assets/index-C3BfKZFO.css +1 -0
- package/studio/ui/dist/assets/ja-BeNkdaEj.js +1 -0
- package/studio/ui/dist/assets/ko-DcTVhdzK.js +1 -0
- package/studio/ui/dist/assets/zh-CN-Cg51ctbL.js +1 -0
- package/studio/ui/dist/index.html +4 -3
- package/studio/ui/dist/assets/ExportCenter-F-2vF-lQ.js +0 -1
- package/studio/ui/dist/assets/SettingsModal-BgVYguNu.js +0 -2
- package/studio/ui/dist/assets/es-BRUzvuoM.js +0 -1
- package/studio/ui/dist/assets/index-Bhg-9dA3.css +0 -1
- package/studio/ui/dist/assets/index-CWur1Iw9.js +0 -1625
- package/studio/ui/dist/assets/ja-Cth-uDcW.js +0 -1
- package/studio/ui/dist/assets/ko-upvw591D.js +0 -1
- 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
|
+
}
|