@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
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 81,
|
|
3
|
+
"name": "Guilloché Security Print",
|
|
4
|
+
"nameZh": "玑镂防伪纹样",
|
|
5
|
+
"family": "Generative & Type",
|
|
6
|
+
"familyZh": "生成艺术与字体",
|
|
7
|
+
"description": "Banknote-grade lathe work: hairline hypotrochoid rosettes and woven sine-ring meshes in split-fountain iris inks on fibred security paper, with engraved serif lettering, microtext and red serials.",
|
|
8
|
+
"motionNotes": "Motion: Like a geometric lathe plotting the plate: the underprint waves and border ropes trace on, each rosette band is drawn pen-pass by pen-pass, the engraved title is wiped in, the red serials are stamped digit by digit; then the meshes slowly counter-rotate into shimmering moiré and a light glint crosses the note.",
|
|
9
|
+
"explainerNotes": "Explainer: A sheet of five security-printed notes the camera pans across; the model is a lathe rosette whose passes start out of register and are brought into register by each correction, with engraved double-rule arrows, red numbering-machine counters and rubber cancellation stamps for WRONG / VERIFIED / CERTIFIED.",
|
|
10
|
+
"code": "code.js",
|
|
11
|
+
"registeredAs": "spirograph",
|
|
12
|
+
"source": "https://www.futurepedia.io/resources/ai-style-atlas/view"
|
|
13
|
+
}
|
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
{
|
|
2
|
+
// ---------- ASCII demoscene: ray-marched torus -> luminance ramp in a monospace grid ----------
|
|
3
|
+
const CW = 8, CH = 12; // cell size in px
|
|
4
|
+
const RAMP = ' .,-~:;=!*#$@'; // the classic donut ramp
|
|
5
|
+
const FLOOR_RAMP = ' .:-=+';
|
|
6
|
+
|
|
7
|
+
// tiny vec helpers
|
|
8
|
+
const len3 = (x, y, z) => Math.sqrt(x * x + y * y + z * z);
|
|
9
|
+
const hsl = (h, s, l, a = 1) => `hsla(${h},${s}%,${l}%,${a})`;
|
|
10
|
+
|
|
11
|
+
// CP437-style block glyphs drawn as real VGA cells: shades are dither patterns, blocks fill the cell exactly
|
|
12
|
+
// (web monospace fonts lack these glyphs and the fallback paints them as flat rectangles).
|
|
13
|
+
// '▓' = solid cell with a staggered 1px hole grid; '▒' = 2px checker; '░' = sparse staggered 2px dots.
|
|
14
|
+
const SHADE_TILE = {
|
|
15
|
+
'▓': (i, j) => !(j % 2 === 0 && (i + j) % 4 === 0),
|
|
16
|
+
'▒': (i, j) => ((i >> 1) + (j >> 1)) % 2 === 0,
|
|
17
|
+
'░': (i, j) => (j >> 1) % 2 === 0 && ((i >> 1) + (j >> 2)) % 2 === 0,
|
|
18
|
+
};
|
|
19
|
+
// coloured shade tiles are cached per (glyph, colour); the colour set is small and fixed, so this fills once
|
|
20
|
+
const shadeCache = new Map();
|
|
21
|
+
const shadeTile = (ch, col) => {
|
|
22
|
+
const key = ch + col; let c = shadeCache.get(key);
|
|
23
|
+
if (!c) {
|
|
24
|
+
if (shadeCache.size > 6000) shadeCache.clear();
|
|
25
|
+
c = H.layer(CW, CH); const g = c.getContext('2d'); g.fillStyle = col;
|
|
26
|
+
const f = SHADE_TILE[ch];
|
|
27
|
+
for (let j = 0; j < CH; j++) for (let i = 0; i < CW; i++) if (f(i, j)) g.fillRect(i, j, 1, 1);
|
|
28
|
+
shadeCache.set(key, c);
|
|
29
|
+
}
|
|
30
|
+
return c;
|
|
31
|
+
};
|
|
32
|
+
function cellGlyph(gx, ch, x, y, col) {
|
|
33
|
+
if (SHADE_TILE[ch]) { gx.drawImage(shadeTile(ch, col), x, y); return true; }
|
|
34
|
+
if (ch === '█') { gx.fillStyle = col; gx.fillRect(x, y, CW, CH); return true; }
|
|
35
|
+
if (ch === '▄') { gx.fillStyle = col; gx.fillRect(x, y + CH / 2, CW, CH / 2); return true; }
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ---------- shared CRT finish: wide phosphor bloom, scanlines, aperture grille (static layers cached by size) ----------
|
|
40
|
+
// Scanlines (28% dark line every 3rd px row) and a 12% RGB aperture grille are both multiplicative, so they are
|
|
41
|
+
// pre-combined into one cached multiply layer.
|
|
42
|
+
let crtKey = '', crtMul = null, crtSmall = null;
|
|
43
|
+
function crtFinish(ctx, glyphs, W, H_) {
|
|
44
|
+
const key = W + 'x' + H_;
|
|
45
|
+
if (crtKey !== key) {
|
|
46
|
+
crtKey = key;
|
|
47
|
+
crtMul = H.layer(W, H_); const g = crtMul.getContext('2d'), img = g.createImageData(W, H_), d = img.data;
|
|
48
|
+
const gr = [[255, 122, 122], [122, 255, 122], [122, 122, 255]];
|
|
49
|
+
for (let y = 0; y < H_; y++) {
|
|
50
|
+
const sl = y % 3 === 2 ? 0.72 : 1;
|
|
51
|
+
for (let x = 0; x < W; x++) {
|
|
52
|
+
const c = gr[x % 3], i = (y * W + x) * 4;
|
|
53
|
+
for (let k = 0; k < 3; k++) d[i + k] = 255 * sl * (1 - 0.12 * (1 - c[k] / 255));
|
|
54
|
+
d[i + 3] = 255;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
g.putImageData(img, 0, 0);
|
|
58
|
+
crtSmall = H.layer(Math.ceil(W / 4), Math.ceil(H_ / 4));
|
|
59
|
+
}
|
|
60
|
+
// second, wider bloom (computed at quarter res, so it is cheap): bright glyphs bleed like phosphor
|
|
61
|
+
const sm = crtSmall.getContext('2d'); sm.clearRect(0, 0, crtSmall.width, crtSmall.height);
|
|
62
|
+
sm.filter = 'blur(3.5px)'; sm.drawImage(glyphs, 0, 0, crtSmall.width, crtSmall.height); sm.filter = 'none';
|
|
63
|
+
ctx.save(); ctx.globalCompositeOperation = 'lighter'; ctx.globalAlpha = 0.35; ctx.drawImage(crtSmall, 0, 0, W, H_);
|
|
64
|
+
ctx.globalCompositeOperation = 'multiply'; ctx.globalAlpha = 1; ctx.drawImage(crtMul, 0, 0);
|
|
65
|
+
ctx.restore();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ================= EXPLAINER: "How does AI learn?" as one long scrolling ASCII document =================
|
|
69
|
+
const FIG = new Map(); // cache: string -> {w, on(x,y)}
|
|
70
|
+
const figBits = (str) => {
|
|
71
|
+
if (FIG.has(str)) return FIG.get(str);
|
|
72
|
+
const w = str.length * 8 + 2, c = H.layer(w, 10), g = c.getContext('2d', { willReadFrequently: true });
|
|
73
|
+
g.font = '8px "Press Start 2P"'; g.textBaseline = 'top'; g.fillStyle = '#fff'; g.fillText(str, 0, 1);
|
|
74
|
+
const d = g.getImageData(0, 0, w, 10).data, bits = new Uint8Array(w * 10);
|
|
75
|
+
for (let i = 0; i < w * 10; i++) bits[i] = d[i * 4 + 3] > 120 ? 1 : 0;
|
|
76
|
+
const res = { w, on: (x, y) => x >= 0 && y >= 0 && x < w && y < 10 && bits[y * w + x] === 1 };
|
|
77
|
+
if (document.fonts && document.fonts.check('8px "Press Start 2P"')) FIG.set(str, res);
|
|
78
|
+
return res;
|
|
79
|
+
};
|
|
80
|
+
const EX_CAT = [' /\\_/\\ ', '( o.o )', ' > ^ < '];
|
|
81
|
+
const EX_DOG = ['/^ ^\\ ', '(o o)__', ' \\_Y_/ '];
|
|
82
|
+
|
|
83
|
+
function asciiExplainer(ctx, W, H_, t) {
|
|
84
|
+
const cols = Math.floor(W / CW), rows = Math.floor(H_ / CH);
|
|
85
|
+
const grid = new Array(cols * rows).fill(null);
|
|
86
|
+
// world-space scroll (terminal scrolls one row at a time = the camera move between beats)
|
|
87
|
+
const sstep = (a, b) => Math.floor(H.ease.inOut(H.clamp((t - a) / (b - a))) * 60);
|
|
88
|
+
const view = sstep(1.8, 2.3) + sstep(6.0, 6.6) + sstep(10.4, 11.0);
|
|
89
|
+
let OFF = view; // world row -> screen row = wr - OFF
|
|
90
|
+
const set = (c, wr, ch, col, bg) => { const r = wr - OFF; c = Math.round(c); if (c >= 0 && r >= 0 && c < cols && r < rows) grid[r * cols + c] = [ch, col, bg]; };
|
|
91
|
+
const put = (c, wr, s, col, bg) => [...s].forEach((ch, i) => set(c + i, wr, ch, col, bg));
|
|
92
|
+
// double-width/double-height line (like a VT100 DECDHL row): occupies 2x2 cells per char
|
|
93
|
+
const bigs = [];
|
|
94
|
+
const put2 = (c, wr, s, col, bg) => { const r = wr - OFF; if (r < -1 || r >= rows) return; bigs.push([Math.round(c), r, s, col, bg]); };
|
|
95
|
+
const ease = (a, d) => H.ease.inOut(H.clamp((t - a) / d));
|
|
96
|
+
const fmt = (n) => String(Math.floor(n)).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
97
|
+
const blink = Math.floor(t * 3) % 2 === 0;
|
|
98
|
+
const flash = (t > 7.5 && t < 7.62) || (t > 12.4 && t < 12.5) ? 25 : 0;
|
|
99
|
+
// figlet text in block characters with a drop shadow
|
|
100
|
+
const fig = (str, c, wr, hueTop, hueBot, reveal = 1, light = 62) => {
|
|
101
|
+
const b = figBits(str), maxX = Math.floor(b.w * reveal);
|
|
102
|
+
for (let y = 0; y < 10; y++) for (let x = 0; x < b.w; x++) {
|
|
103
|
+
if (x > maxX) continue;
|
|
104
|
+
if (b.on(x, y)) { const k = y / 8; set(c + x, wr + y, k < 0.55 ? '█' : '▓', hsl(H.lerp(hueTop, hueBot, k), 100, light + flash - k * 10)); }
|
|
105
|
+
else if (b.on(x - 1, y - 1)) set(c + x, wr + y, '░', hsl(300, 80, 30));
|
|
106
|
+
}
|
|
107
|
+
return b.w;
|
|
108
|
+
};
|
|
109
|
+
const box = (c, wr, w, h, col, title, prog = 1) => {
|
|
110
|
+
const perim = [];
|
|
111
|
+
for (let i = 0; i < w; i++) perim.push([c + i, wr, i === 0 ? '┌' : i === w - 1 ? '┐' : '─']);
|
|
112
|
+
for (let j = 1; j < h; j++) perim.push([c + w - 1, wr + j, j === h - 1 ? '┘' : '│']);
|
|
113
|
+
for (let i = w - 2; i >= 0; i--) perim.push([c + i, wr + h - 1, i === 0 ? '└' : '─']);
|
|
114
|
+
for (let j = h - 2; j >= 1; j--) perim.push([c, wr + j, '│']);
|
|
115
|
+
const n = Math.floor(perim.length * prog);
|
|
116
|
+
for (let k = 0; k < n; k++) set(perim[k][0], perim[k][1], perim[k][2], col);
|
|
117
|
+
if (title && prog >= 1) put(c + 2, wr, ' ' + title + ' ', '#ffffff', hsl(185, 90, 30));
|
|
118
|
+
};
|
|
119
|
+
const hArrow = (c0, c1, wr, col, prog = 1, label) => {
|
|
120
|
+
const end = Math.floor(c0 + (c1 - c0) * prog);
|
|
121
|
+
for (let c = c0; c < end; c++) set(c, wr, '─', col);
|
|
122
|
+
if (prog > 0.05) set(end, wr, '►', col);
|
|
123
|
+
if (label && prog >= 1) put(Math.round((c0 + c1) / 2 - label.length / 2), wr - 1, label, col);
|
|
124
|
+
};
|
|
125
|
+
const pathArrow = (pts, col, prog, head) => { // pts: [[c,wr]...] axis-aligned
|
|
126
|
+
const cells = [];
|
|
127
|
+
for (let i = 1; i < pts.length; i++) {
|
|
128
|
+
const [c0, r0] = pts[i - 1], [c1, r1] = pts[i];
|
|
129
|
+
const n = Math.max(Math.abs(c1 - c0), Math.abs(r1 - r0));
|
|
130
|
+
for (let k = 0; k < n; k++) cells.push([c0 + Math.sign(c1 - c0) * k, r0 + Math.sign(r1 - r0) * k, r0 === r1 ? '─' : '│']);
|
|
131
|
+
}
|
|
132
|
+
const n = Math.floor(cells.length * prog);
|
|
133
|
+
for (let k = 0; k < n; k++) set(cells[k][0], cells[k][1], cells[k][2], col);
|
|
134
|
+
if (n > 0 && n <= cells.length) { const [c, r] = cells[Math.min(n, cells.length) - 1]; set(c, r, n < cells.length ? '●' : head, col); }
|
|
135
|
+
};
|
|
136
|
+
const net = (c, wr, wobble, settle) => { // little network of nodes + connections inside a box
|
|
137
|
+
const L = [[c + 4, [wr + 3, wr + 8, wr + 13]], [c + 18, [wr + 1, wr + 6, wr + 11, wr + 16]], [c + 32, [wr + 5, wr + 10]]];
|
|
138
|
+
for (let l = 0; l < 2; l++) L[l][1].forEach((ra, i) => L[l + 1][1].forEach((rb, j) => {
|
|
139
|
+
const x0 = L[l][0], x1 = L[l + 1][0], n = x1 - x0;
|
|
140
|
+
const id = l * 20 + i * 4 + j;
|
|
141
|
+
const strong = H.rng(id + (settle ? 99 : 0))() > 0.5;
|
|
142
|
+
const hot = wobble > 0 && H.rng(id + Math.floor(t * 12))() > 0.6;
|
|
143
|
+
for (let k = 1; k < n; k++) { const rr = Math.round(H.lerp(ra, rb, k / n)); set(x0 + k, rr, strong ? '·' : '.', hot ? hsl(0, 90, 60) : hsl(185, 70, strong ? 55 : 32)); }
|
|
144
|
+
}));
|
|
145
|
+
L.forEach(([x, rs]) => rs.forEach((rr) => { set(x, rr, 'O', hsl(48, 100, 65 + (wobble ? 15 : 0))); }));
|
|
146
|
+
};
|
|
147
|
+
const asciiPic = (rowsA, c, wr, col) => rowsA.forEach((s, i) => put(c, wr + i, s, col));
|
|
148
|
+
|
|
149
|
+
// ---------- plasma backdrop (screen-space, very dim) ----------
|
|
150
|
+
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
|
|
151
|
+
const x = c / cols, y = (r + view) / rows;
|
|
152
|
+
const v = Math.sin(x * 9 + t) + Math.sin(y * 7 - t * 0.7) + Math.sin((x + y) * 6 + t * 0.5);
|
|
153
|
+
const k = (v + 3) / 6; if (k < 0.5) continue;
|
|
154
|
+
const u = (k - 0.5) / 0.5;
|
|
155
|
+
grid[r * cols + c] = ['.·:'[Math.min(2, Math.floor(u * 3))], hsl(250 + k * 60, 66, 14 + u * 22, 0.6 + u * 0.3)];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ---------- BEAT 1 (world rows 0-59): the question, big ----------
|
|
159
|
+
fig('HOW DOES', 48, 16, 48, -20, H.clamp((t - 0.1) / 0.6));
|
|
160
|
+
fig('AI LEARN?', 44, 28, 48, -20, H.clamp((t - 0.6) / 0.7));
|
|
161
|
+
if (t > 1.2) put(52, 41, '> scroll down for the answer_', hsl(185, 70, 55));
|
|
162
|
+
|
|
163
|
+
// ---------- BEAT 2 (world rows 60-119): labelled data stream into the model ----------
|
|
164
|
+
{
|
|
165
|
+
const B = 60;
|
|
166
|
+
// model box with its network
|
|
167
|
+
box(80, B + 8, 40, 22, hsl(185, 90, 50), 'MODEL', ease(1.85, 0.5));
|
|
168
|
+
if (t > 2.2) net(81, B + 10, 0, false);
|
|
169
|
+
// the flow arrow with its label
|
|
170
|
+
hArrow(2, 78, B + 26, hsl(48, 100, 60), ease(2.0, 0.6)); if (t > 3.0) put2(14, B + 28, 'training data', hsl(48, 100, 62));
|
|
171
|
+
// labelled example cards marching (cell-stepped) along the arrow into the model
|
|
172
|
+
for (let i = 0; i < 7; i++) {
|
|
173
|
+
const t0 = 2.5 + i * 0.5, k = (t - t0) / 1.6;
|
|
174
|
+
if (k < 0 || k > 1) continue;
|
|
175
|
+
const c = Math.floor(H.lerp(-20, 62, k)), isCat = i % 3 !== 1;
|
|
176
|
+
box(c, B + 11, 18, 9, hsl(300, 60, 55));
|
|
177
|
+
(isCat ? EX_CAT : EX_DOG).forEach((rw, j) => put2(c + 2, B + 12 + j * 2, rw, '#ffffff'));
|
|
178
|
+
put2(c + 6, B + 21, isCat ? 'cat' : 'dog', '#000', isCat ? hsl(48, 100, 60) : hsl(330, 100, 65));
|
|
179
|
+
}
|
|
180
|
+
// counter as figlet digits, label landing on it
|
|
181
|
+
if (t > 2.9) {
|
|
182
|
+
const v = 1e6 * Math.pow(H.clamp((t - 3.0) / 2.6), 2.2);
|
|
183
|
+
fig(fmt(v), 46, B + 36, 185, 260, 1, 60);
|
|
184
|
+
put2(46, B + 47, 'examples seen ^', hsl(185, 70, 60));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ---------- BEAT 3 (world rows 120-179): GUESS -> CHECK -> ADJUST ----------
|
|
189
|
+
{
|
|
190
|
+
const B = 120;
|
|
191
|
+
const phase = t < 7.5 ? 0 : t < 8.35 ? 1 : t < 9.4 ? 2 : 0;
|
|
192
|
+
['GUESS', 'CHECK', 'ADJUST'].forEach((nm, i) => {
|
|
193
|
+
const c = 24 + i * 34, on = i === phase && t > 6.3;
|
|
194
|
+
put2(c, B + 4, ' ' + nm + ' ', on ? '#000' : hsl(185, 60, 55), on ? hsl(48, 100, 60) : undefined);
|
|
195
|
+
if (i < 2) put(c + nm.length * 2 + 6, B + 5, '──►', hsl(185, 60, 50));
|
|
196
|
+
});
|
|
197
|
+
put(106, B + 5, '─┐', hsl(185, 60, 50)); put(107, B + 6, '│', hsl(185, 60, 50)); put(107, B + 7, '│', hsl(185, 60, 50));
|
|
198
|
+
put(30, B + 8, '└' + '─'.repeat(76) + '┘', hsl(185, 60, 50)); set(30, B + 7, '▲', hsl(185, 60, 50)); put2(60, B + 9, 'repeat', hsl(185, 60, 50));
|
|
199
|
+
// picture
|
|
200
|
+
box(1, B + 15, 18, 8, hsl(300, 60, 55)); EX_CAT.forEach((rw, j) => put2(3, B + 16 + j * 2, rw, '#ffffff')); put2(2, B + 24, 'picture', hsl(300, 50, 70));
|
|
201
|
+
// model
|
|
202
|
+
const wob = t > 8.6 && t < 9.4 ? 1 : 0;
|
|
203
|
+
box(46, B + 12, 40, 22, hsl(185, 90, 50), 'MODEL');
|
|
204
|
+
net(47, B + 14, wob, t > 9.0);
|
|
205
|
+
// weights readout inside the model
|
|
206
|
+
const adj = H.clamp((t - 8.6) / 0.7), wv = [[0.42, 0.57], [-1.3, -0.86], [0.77, 0.31]];
|
|
207
|
+
wv.forEach(([a, b], i) => { let v = H.lerp(a, b, adj); if (adj > 0 && adj < 1) v += (H.rng(Math.floor(t * 15) + i)() - 0.5) * 0.5; put2(30 + i * 19, B + 42, 'w' + (i + 1) + '=' + (v >= 0 ? '+' : '') + v.toFixed(2), adj > 0 && adj < 1 ? hsl(0, 90, 65) : hsl(48, 80, 60)); });
|
|
208
|
+
hArrow(20, 45, B + 20, hsl(48, 100, 60), ease(6.7, 0.4)); if (t > 6.9) put2(24, B + 17, 'guess', hsl(48, 100, 62));
|
|
209
|
+
if (t > 7.0) hArrow(87, 98, B + 20, hsl(48, 100, 60), ease(7.0, 0.2));
|
|
210
|
+
if (t > 7.1 && t < 9.4) {
|
|
211
|
+
fig('dog?', 100, B + 16, t > 7.5 ? 10 : 48, -20, H.clamp((t - 7.1) / 0.3));
|
|
212
|
+
if (t > 7.5) {
|
|
213
|
+
for (let k = 0; k < 9; k++) { set(102 + k * 3, B + 16 + k, '╲', hsl(0, 100, 60)); set(103 + k * 3, B + 16 + k, '╲', hsl(0, 100, 60)); set(127 - k * 3, B + 16 + k, '╱', hsl(0, 100, 60)); set(128 - k * 3, B + 16 + k, '╱', hsl(0, 100, 60)); }
|
|
214
|
+
if (t > 8.2 || blink) put2(98, B + 27, " X it's a cat ", '#000', hsl(0, 100, 60));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (t > 8.35) { // error travels back to the model
|
|
218
|
+
pathArrow([[114, B + 29], [114, B + 38], [66, B + 38], [66, B + 34]], hsl(0, 100, 62), ease(8.35, 0.55), '▲');
|
|
219
|
+
if (t > 8.6) put2(80, B + 39, 'error', hsl(0, 100, 70));
|
|
220
|
+
}
|
|
221
|
+
if (t > 9.75) {
|
|
222
|
+
fig('cat', 100, B + 16, 120, 160, H.clamp((t - 9.75) / 0.3));
|
|
223
|
+
if (t > 10.0) { const CK = ['......██', '.....██.', '██..██..', '.████...', '..██....']; CK.forEach((rw, j) => [...rw].forEach((ch, i) => { if (ch === '█') set(126 + i, B + 17 + j, '█', hsl(130, 100, 60)); })); put2(98, B + 27, ' correct! ', '#000', hsl(130, 90, 55)); }
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ---------- BEAT 4 + 5 (world rows 180-239): accuracy chart, then the takeaway ----------
|
|
228
|
+
{
|
|
229
|
+
const B = 180;
|
|
230
|
+
const ox = 10, oy = B + 32, ah = 24;
|
|
231
|
+
for (let r = 0; r <= ah; r++) set(ox, oy - r, '│', hsl(185, 60, 50));
|
|
232
|
+
put(ox, oy, '└' + '─'.repeat(84), hsl(185, 60, 50));
|
|
233
|
+
put(ox - 6, oy - ah, '100%', hsl(185, 60, 60)); put(ox - 5, oy - ah / 2, '50%', hsl(185, 60, 60));
|
|
234
|
+
put2(ox + 40, oy + 1, 'training rounds >', hsl(185, 60, 60));
|
|
235
|
+
const acc = (i) => 97 - 36 * Math.exp(-i / 4);
|
|
236
|
+
const nb = H.clamp((t - 11.0) / 1.4) * 16;
|
|
237
|
+
for (let i = 0; i < 16; i++) {
|
|
238
|
+
const g = H.clamp(nb - i); if (g <= 0) break;
|
|
239
|
+
const h = Math.round((acc(i) / 100) * ah * g);
|
|
240
|
+
for (let r = 1; r <= h; r++) for (let w = 0; w < 4; w++) {
|
|
241
|
+
const ch = r === h ? '▄' : w === 0 ? '▓' : w === 3 ? '▒' : '█';
|
|
242
|
+
set(ox + 2 + i * 5 + w, oy - r, ch, hsl(260 - i * 8, 90, 45 + r * 1.2 - (r % 2) * 6 - (w === 3 ? 8 : 0)));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const val = Math.round(61 + 36 * H.ease.out(H.clamp((t - 11.0) / 1.4)));
|
|
246
|
+
put2(104, B + 8, 'accuracy', hsl(185, 70, 60));
|
|
247
|
+
fig(val + '%', 104, B + 11, 48, -20, 1);
|
|
248
|
+
if (t > 12.4) {
|
|
249
|
+
if (t > 12.9 || blink) { put(101, B + 9, '╔' + '═'.repeat(36) + '╗', hsl(0, 100, 62)); put(101, B + 22, '╚' + '═'.repeat(36) + '╝', hsl(0, 100, 62)); for (let r = B + 10; r < B + 22; r++) { set(101, r, '║', hsl(0, 100, 62)); set(138, r, '║', hsl(0, 100, 62)); } }
|
|
250
|
+
pathArrow([[100, B + 15], [90, B + 15]], hsl(0, 100, 62), ease(12.4, 0.25), '◄');
|
|
251
|
+
put2(104, B + 23, '61% > ' + val + '%', hsl(48, 100, 62));
|
|
252
|
+
}
|
|
253
|
+
if (t > 13.0) {
|
|
254
|
+
fig('MORE EXAMPLES', 16, B + 38, 185, 260, H.clamp((t - 13.0) / 0.45));
|
|
255
|
+
fig('>BETTER GUESSES', 16, B + 49, 48, -20, H.clamp((t - 13.35) / 0.5));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ---------- pinned header: the question lives on as a title bar ----------
|
|
260
|
+
if (t > 2.1) {
|
|
261
|
+
for (let r = 0; r < 4; r++) for (let c = 0; c < cols; c++) grid[r * cols + c] = null;
|
|
262
|
+
for (let i = bigs.length - 1; i >= 0; i--) if (bigs[i][1] < 4) bigs.splice(i, 1);
|
|
263
|
+
OFF = 0;
|
|
264
|
+
const k = H.clamp((t - 2.1) / 0.3), q = ' HOW DOES AI LEARN? ';
|
|
265
|
+
put(2 + q.length * 2 + 1, 2, '─'.repeat(Math.floor((cols - q.length * 2 - 22) * k)), hsl(48, 80, 45));
|
|
266
|
+
const beat = t < 6.3 ? '1/4 data' : t < 10.7 ? '2/4 learn loop' : t < 13 ? '3/4 progress' : '4/4 takeaway';
|
|
267
|
+
put(cols - beat.length - 3, 2, beat, hsl(185, 70, 60));
|
|
268
|
+
put2(2, 1, q.slice(0, Math.ceil(q.length * k)), '#000', hsl(48, 100, 60));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ---------- render cells: backgrounds, glyphs, glow ----------
|
|
272
|
+
const glyphs = H.layer(W, H_), gx = glyphs.getContext('2d');
|
|
273
|
+
ctx.fillStyle = '#05040a'; ctx.fillRect(0, 0, W, H_);
|
|
274
|
+
gx.font = '600 12px "IBM Plex Mono"'; gx.textBaseline = 'top';
|
|
275
|
+
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
|
|
276
|
+
const g = grid[r * cols + c]; if (!g) continue;
|
|
277
|
+
if (g[2]) { gx.fillStyle = g[2]; gx.fillRect(c * CW, r * CH, CW, CH); }
|
|
278
|
+
if (g[0] !== ' ' && !cellGlyph(gx, g[0], c * CW, r * CH, g[1])) { gx.fillStyle = g[1]; gx.fillText(g[0], c * CW, r * CH); }
|
|
279
|
+
}
|
|
280
|
+
gx.font = '600 28px "IBM Plex Mono"'; gx.textBaseline = 'middle'; gx.textAlign = 'center';
|
|
281
|
+
bigs.forEach(([c, r, str, col, bg]) => {
|
|
282
|
+
gx.clearRect(c * CW, r * CH, str.length * 2 * CW, 2 * CH);
|
|
283
|
+
if (bg) { gx.fillStyle = bg; gx.fillRect(c * CW, r * CH, str.length * 2 * CW, 2 * CH); }
|
|
284
|
+
gx.fillStyle = col; [...str].forEach((ch, i) => gx.fillText(ch, (c + i * 2) * CW + CW, r * CH + CH + 1));
|
|
285
|
+
});
|
|
286
|
+
gx.textAlign = 'left';
|
|
287
|
+
ctx.save(); ctx.globalCompositeOperation = 'lighter'; ctx.globalAlpha = 0.8; ctx.filter = 'blur(6px)'; ctx.drawImage(glyphs, 0, 0); ctx.restore();
|
|
288
|
+
ctx.drawImage(glyphs, 0, 0);
|
|
289
|
+
crtFinish(ctx, glyphs, W, H_);
|
|
290
|
+
H.vignette(ctx, W, H_, 0.55);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ================= SOUND: a demoscene terminal. Characters print with dry little clicks, the terminal scrolls with a
|
|
294
|
+
// stepped line-feed rattle and a falling SID sweep, a quiet tracker (chip) tune runs under each beat, and the big hits
|
|
295
|
+
// are square-wave chord stabs with a noise-channel crash. Times copied from asciiExplainer above.
|
|
296
|
+
function asciiSound(k) {
|
|
297
|
+
const END = 14.5;
|
|
298
|
+
const pan = (c) => H.clamp(c / 160) * 1.6 - 0.8; // 160 columns across the 1280 px screen
|
|
299
|
+
const sq = (t, f, dur, gain, o) => k.tone(t, Object.assign({ f, type: 'square', dur, gain, a: 0.001, hold: dur * 0.6, filter: 'lowpass', f2: 2600 }, o));
|
|
300
|
+
const tri = (t, f, dur, gain, o) => k.tone(t, Object.assign({ f, type: 'triangle', dur, gain, a: 0.002, hold: dur * 0.5 }, o));
|
|
301
|
+
const crash = (t, dur, gain, p = 0) => k.noise(t, { dur, filter: 'lowpass', f: 3500, gain, rate: 0.3, a: 0.001, pan: p });
|
|
302
|
+
// one printed character: a dry terminal click with a low body (no pitched chirp)
|
|
303
|
+
const chr = (t, p = 0, g = 1) => { k.noise(t, { dur: 0.012, filter: 'bandpass', f: 1500, q: 2.5, gain: 0.2 * g, a: 0.001, pan: p, minor: true }); k.tone(t, { f: 190, type: 'square', dur: 0.018, gain: 0.03 * g, a: 0.001, filter: 'lowpass', f2: 700, pan: p, minor: true }); };
|
|
304
|
+
// print a stretch of text: one click per frame-ish, kept to ~14/s
|
|
305
|
+
const print = (t0, dur, p = 0, g = 1) => { for (let t = t0; t < t0 + dur - 0.01; t += 1 / 14) chr(t, p, g); };
|
|
306
|
+
// terminal scroll a -> b (eased, 60 rows): line-feed rattle that speeds up and slows with the ease, plus a falling sweep
|
|
307
|
+
const scroll = (a, b) => {
|
|
308
|
+
let row = 0;
|
|
309
|
+
for (let f = Math.ceil(a * 60); f <= b * 60; f++) {
|
|
310
|
+
const t = f / 60, r = Math.floor(H.ease.inOut(H.clamp((t - a) / (b - a))) * 60);
|
|
311
|
+
if (r - row >= 4) { k.noise(t, { dur: 0.01, filter: 'bandpass', f: 900, q: 3, gain: 0.16, a: 0.001 }); row = r; }
|
|
312
|
+
}
|
|
313
|
+
k.tone(a, { f: [[0, 700], [b - a, 110]], type: 'square', dur: b - a + 0.05, gain: 0.04, a: (b - a) * 0.3, filter: 'lowpass', f2: 1600 });
|
|
314
|
+
k.noise(a, { dur: b - a, color: 'pink', filter: 'bandpass', f: [[0, 1800], [b - a, 400]], q: 1.2, gain: 0.08, a: (b - a) * 0.4 });
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// ---- tracker tune under each beat (drops out for the scrolls)
|
|
318
|
+
const BPM = 125;
|
|
319
|
+
k.music('chip', 0.1, 1.8, { bpm: BPM, gain: 0.25, chords: [['A3', 'C4', 'E4', 'A4']] });
|
|
320
|
+
k.music('chip', 2.3, 6.0, { bpm: BPM, gain: 0.4, chords: [['A3', 'C4', 'E4', 'A4'], ['F3', 'A3', 'C4', 'F4']] });
|
|
321
|
+
k.music('chip', 6.6, 10.4, { bpm: BPM, gain: 0.4, chords: [['D4', 'F4', 'A4', 'D5'], ['E3', 'G#3', 'B3', 'E4']] });
|
|
322
|
+
k.music('chip', 11.0, END, { bpm: BPM, gain: 0.3, chords: [['C4', 'E4', 'G4', 'C5'], ['F3', 'A3', 'C4', 'F4']] });
|
|
323
|
+
k.bed('hiss', 0, END, { gain: 0.8 });
|
|
324
|
+
|
|
325
|
+
// ---- BEAT 1: figlet question prints column by column (0.1-0.7, 0.6-1.3), prompt line (1.2)
|
|
326
|
+
print(0.1, 0.6, pan(70)); print(0.62, 0.68, pan(70));
|
|
327
|
+
sq(1.2, 'A3', 0.05, 0.05, { pan: pan(80) }); chr(1.2, pan(80), 1.4);
|
|
328
|
+
scroll(1.8, 2.3);
|
|
329
|
+
|
|
330
|
+
// ---- BEAT 2: header pins (2.1), MODEL box draws (1.85-2.35), arrow draws (2.0-2.6)
|
|
331
|
+
sq(2.1, 'E3', 0.07, 0.04, { pan: -0.5 }); sq(2.17, 'A3', 0.09, 0.035, { pan: -0.5 }); // reverse-video title bar snaps on
|
|
332
|
+
print(2.35, 0.25, pan(40), 0.7); // arrow line finishes drawing
|
|
333
|
+
chr(3.0, pan(30), 1.3); // 'training data' label
|
|
334
|
+
// cards reach the MODEL (k = 1 at 2.5 + i*0.5 + 1.6) while it is on screen: a rising square gulp
|
|
335
|
+
[4.1, 4.6, 5.1, 5.6].forEach((t, i) => k.tone(t, { f: [[0, 330 * Math.pow(2, i / 12)], [0.07, 660 * Math.pow(2, i / 12)]], type: 'square', dur: 0.09, gain: 0.05, a: 0.001, hold: 0.05, filter: 'lowpass', f2: 2000, pan: pan(84), minor: true }));
|
|
336
|
+
// counter 3.0-5.6 (pow 2.2, speeding up): noise-channel ticks, sparse to dense, capped at 12/s
|
|
337
|
+
for (let t = 3.05; t < 5.55;) { k.noise(t, { dur: 0.015, filter: 'bandpass', f: 2200, q: 2, gain: 0.14, a: 0.001, pan: pan(70), minor: true }); t += H.lerp(0.25, 1 / 12, (t - 3.0) / 2.6); }
|
|
338
|
+
// lands on 1,000,000 (5.6)
|
|
339
|
+
['A4', 'C5', 'E5'].forEach((n) => sq(5.6, n, 0.3, 0.032, { pan: pan(70) })); tri(5.6, 'A2', 0.3, 0.15); crash(5.6, 0.12, 0.08);
|
|
340
|
+
scroll(6.0, 6.6);
|
|
341
|
+
|
|
342
|
+
// ---- BEAT 3: GUESS lights (6.3), guess arrow (6.7-7.1), "dog?" prints (7.1-7.4)
|
|
343
|
+
sq(6.3, 'D4', 0.05, 0.05, { pan: pan(30) });
|
|
344
|
+
print(6.75, 0.3, pan(32), 0.7); chr(6.9, pan(28), 1.2);
|
|
345
|
+
print(7.1, 0.3, pan(110));
|
|
346
|
+
// CHECK (7.5): the wrong guess. screen flash, dog? turns red and is crossed out
|
|
347
|
+
sq(7.5, 'A2', 0.35, 0.09, { f2: 1200, hold: 0.25, pan: pan(110) }); sq(7.5, 'A#2', 0.35, 0.07, { f2: 1200, hold: 0.25, pan: pan(110) }); // detuned buzz
|
|
348
|
+
k.play('glitch', 7.5, { gain: 1.0, pan: pan(110) }); crash(7.5, 0.25, 0.18, pan(110));
|
|
349
|
+
sq(7.85, 'E2', 0.25, 0.07, { f2: 900, hold: 0.15, pan: pan(100) }); // "X it's a cat" label settles under it
|
|
350
|
+
// ADJUST (8.35): button, red error path runs back to the model (8.35-8.9), 'error' label (8.6)
|
|
351
|
+
sq(8.35, 'D4', 0.05, 0.05, { pan: pan(100) });
|
|
352
|
+
k.tone(8.35, { f: [[0, 900], [0.55, 220]], type: 'square', dur: 0.56, gain: 0.04, a: 0.01, hold: 0.4, filter: 'lowpass', f2: 1500, pan: 0.5 });
|
|
353
|
+
// weights + network jitter while adjusting (8.6-9.3, re-rolls 15x/s): low random square burble, then it settles
|
|
354
|
+
k.withMinor(() => { const r = H.rng(808); for (let t = 8.6; t < 9.3; t += 1 / 15) sq(t, 110 + r() * 260, 0.05, 0.035, { f2: 900, pan: -0.2 + r() * 0.4 }); });
|
|
355
|
+
sq(9.3, 'A3', 0.08, 0.05, { pan: -0.3 });
|
|
356
|
+
sq(9.4, 'D4', 0.05, 0.05, { pan: pan(30) }); // GUESS again
|
|
357
|
+
// "cat" prints (9.75-10.05), check + correct! (10.0): the correction
|
|
358
|
+
print(9.75, 0.25, pan(110));
|
|
359
|
+
['D5', 'F#5', 'A5'].forEach((n, i) => sq(10.0 + i * 0.06, n, 0.08, 0.04, { pan: pan(115) })); sq(10.18, 'D6', 0.3, 0.03, { pan: pan(115) }); tri(10.0, 'D3', 0.35, 0.14);
|
|
360
|
+
scroll(10.4, 11.0);
|
|
361
|
+
|
|
362
|
+
// ---- BEAT 4: 16 bars grow one after another (11.0 + i*0.0875), the % climbs with them
|
|
363
|
+
k.withMinor(() => { const notes = ['C4', 'E4', 'G4', 'C5']; for (let i = 0; i < 16; i++) sq(11.0 + i * 0.0875, k.hz(notes[i % 4]) * (i < 8 ? 1 : 2) * 0.5, 0.06, 0.04, { f2: 1800, pan: pan(12 + i * 5) }); });
|
|
364
|
+
// 97% (12.4): boxed + flashed. the biggest hit: chord stab, kick, crash, and an arrow ping
|
|
365
|
+
const P = 12.4;
|
|
366
|
+
['C4', 'E4', 'G4', 'C5', 'E5'].forEach((n) => sq(P, n, 0.8, 0.055, { hold: 0.3, pan: pan(118), verb: 0.15 }));
|
|
367
|
+
tri(P, 'C2', 0.7, 0.32, { hold: 0.2 }); k.play('thud', P, { f: 120, gain: 0.7 }); crash(P, 0.5, 0.26, pan(118));
|
|
368
|
+
// ---- BEAT 5: takeaway prints (13.0-13.45, 13.35-13.85) and lands (13.85)
|
|
369
|
+
print(13.0, 0.4, pan(60)); print(13.38, 0.45, pan(60));
|
|
370
|
+
const TAKE = 13.85;
|
|
371
|
+
sq(TAKE, 'G4', 0.1, 0.035); ['C5', 'E5', 'G5'].forEach((n) => sq(TAKE + 0.1, n, 0.6, 0.026, { hold: 0.2, verb: 0.12 })); tri(TAKE + 0.1, 'C3', 0.7, 0.13);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
registerStyle({
|
|
375
|
+
id: 'ascii-render',
|
|
376
|
+
name: 'ASCII Demoscene',
|
|
377
|
+
category: 'Retro Digital',
|
|
378
|
+
description: 'A ray-marched 3D torus rasterised into a strict monospace character grid via a luminance ramp, colour-coded like a 90s demoscene intro: box-drawn title panel, plasma backdrop, copper bars and a sine scroller.',
|
|
379
|
+
motion: 'Like a demo intro booting: plasma thickens in, the spinning torus is rastered into characters top-to-bottom behind a bright scan row, the block title and nfo panel print, copper bars open and a rainbow sine-scroller glides in from the right.',
|
|
380
|
+
duration: 5,
|
|
381
|
+
fonts: ['600 12px "IBM Plex Mono"', '700 22px "IBM Plex Mono"', '8px "Press Start 2P"'],
|
|
382
|
+
frameT: 4.7,
|
|
383
|
+
readsPixels: false,
|
|
384
|
+
explainerDuration: 14.5,
|
|
385
|
+
explainerNote: 'One long ASCII document that the terminal scrolls through row by row: figlet block-letter question, labelled ASCII cat/dog cards stepping along a box-drawing arrow into a MODEL box, a reverse-video GUESS/CHECK/ADJUST loop with a red error path, and block-character bar charts with figlet counters.',
|
|
386
|
+
explainer(ctx, W, H_, t) { asciiExplainer(ctx, W, H_, t); },
|
|
387
|
+
explainerSound(k) { asciiSound(k); },
|
|
388
|
+
draw(ctx, W, H_, t) {
|
|
389
|
+
const cols = Math.floor(W / CW), rows = Math.floor(H_ / CH);
|
|
390
|
+
const nz = H.makeNoise(31);
|
|
391
|
+
ctx.fillStyle = '#05040a'; ctx.fillRect(0, 0, W, H_);
|
|
392
|
+
|
|
393
|
+
// grid of {ch, color}
|
|
394
|
+
const grid = new Array(cols * rows).fill(null);
|
|
395
|
+
const set = (c, r, ch, col) => { if (c >= 0 && r >= 0 && c < cols && r < rows) grid[r * cols + c] = [ch, col]; };
|
|
396
|
+
|
|
397
|
+
// ---------- 1. plasma backdrop (very dim) ----------
|
|
398
|
+
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
|
|
399
|
+
const x = c / cols, y = r / rows;
|
|
400
|
+
const v = Math.sin(x * 9 + t) + Math.sin(y * 7 - t * 0.7) + Math.sin((x + y) * 6 + t * 0.5) + Math.sin(Math.hypot(x - 0.5, y - 0.5) * 14 - t * 1.3);
|
|
401
|
+
const k = (v + 4) / 8;
|
|
402
|
+
const thr = 0.45 + (1 - Math.floor(H.clamp(t / 0.8) * 6) / 6) * 0.55;
|
|
403
|
+
if (k < thr) continue;
|
|
404
|
+
const ch = '.·:+'[Math.min(3, Math.floor((k - 0.45) / 0.55 * 4))];
|
|
405
|
+
set(c, r, ch, hsl(250 + k * 60, 60, 14 + k * 16));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// ---------- 2. ray-marched torus + checker floor ----------
|
|
409
|
+
const A = 1.12 + (t - 4.7) * 0.36, Bang = 0.36 + (t - 4.7) * 0.32;
|
|
410
|
+
const cA = Math.cos(A), sA = Math.sin(A), cB = Math.cos(Bang), sB = Math.sin(Bang);
|
|
411
|
+
const R1 = 0.46, R2 = 1.05, FLOOR = -1.75;
|
|
412
|
+
// object-space rotate (inverse rotation of the point)
|
|
413
|
+
const rot = (x, y, z) => {
|
|
414
|
+
// rotate around X by A, then around Z by B
|
|
415
|
+
let y1 = y * cA - z * sA, z1 = y * sA + z * cA;
|
|
416
|
+
let x2 = x * cB - y1 * sB, y2 = x * sB + y1 * cB;
|
|
417
|
+
return [x2, y2, z1];
|
|
418
|
+
};
|
|
419
|
+
const sdTorus = (x, y, z) => { const [px, py, pz] = rot(x, y, z); const q = Math.hypot(px, pz) - R2; return Math.hypot(q, py) - R1; };
|
|
420
|
+
const scene = (x, y, z) => Math.min(sdTorus(x, y, z), y - FLOOR);
|
|
421
|
+
const camX = 0, camY = 0.75, camZ = -4.6;
|
|
422
|
+
const Lx0 = Math.cos((t - 4.7) * 0.4 + 0.88) * 0.6 - 0.5, Ly0 = 0.9, Lz0 = -0.7, Ll = len3(Lx0, Ly0, Lz0);
|
|
423
|
+
const Lx = Lx0 / Ll, Ly = Ly0 / Ll, Lz = Lz0 / Ll;
|
|
424
|
+
// torus centred at ~ (760px, 330px)
|
|
425
|
+
const cxPx = 820, cyPx = 300, scale = 430;
|
|
426
|
+
const march = (ox, oy, oz, dx, dy, dz) => {
|
|
427
|
+
let d = 0;
|
|
428
|
+
for (let i = 0; i < 80; i++) {
|
|
429
|
+
const h = scene(ox + dx * d, oy + dy * d, oz + dz * d);
|
|
430
|
+
if (h < 0.002) return d;
|
|
431
|
+
d += h; if (d > 22) break;
|
|
432
|
+
}
|
|
433
|
+
return -1;
|
|
434
|
+
};
|
|
435
|
+
const softShadow = (ox, oy, oz) => {
|
|
436
|
+
let res = 1, d = 0.04;
|
|
437
|
+
for (let i = 0; i < 40 && d < 6; i++) { const h = sdTorus(ox + Lx * d, oy + Ly * d, oz + Lz * d); if (h < 0.001) return 0; res = Math.min(res, 8 * h / d); d += h; }
|
|
438
|
+
return H.clamp(res);
|
|
439
|
+
};
|
|
440
|
+
const c0 = Math.floor((cxPx - 560) / CW), c1 = Math.ceil((cxPx + 560) / CW);
|
|
441
|
+
const r0 = Math.floor((cyPx - 300) / CH), r1 = Math.min(rows - 9, Math.ceil((cyPx + 360) / CH));
|
|
442
|
+
const scanRow = Math.floor(r0 + H.clamp((t - 0.3) / 1.2) * (r1 - r0 + 1));
|
|
443
|
+
for (let r = Math.max(0, r0); r < Math.min(r1, scanRow + 1); r++) for (let c = Math.max(0, c0); c < Math.min(cols, c1); c++) {
|
|
444
|
+
let lumSum = 0, hits = 0, kind = 0, angSum = 0, depth = 0, specSum = 0;
|
|
445
|
+
for (let sy = 0; sy < 2; sy++) for (let sx = 0; sx < 2; sx++) {
|
|
446
|
+
const px = (c * CW + (sx + 0.5) * CW / 2 - cxPx) / scale, py = -(r * CH + (sy + 0.5) * CH / 2 - cyPx) / scale;
|
|
447
|
+
let dx = px, dy = py - 0.12, dz = 1.6; const dl = len3(dx, dy, dz); dx /= dl; dy /= dl; dz /= dl;
|
|
448
|
+
const d = march(camX, camY, camZ, dx, dy, dz);
|
|
449
|
+
if (d < 0) continue;
|
|
450
|
+
const hx = camX + dx * d, hy = camY + dy * d, hz = camZ + dz * d;
|
|
451
|
+
const isFloor = Math.abs(hy - FLOOR) < 0.004 && sdTorus(hx, hy, hz) > 0.004;
|
|
452
|
+
if (isFloor) {
|
|
453
|
+
const chk = ((Math.floor(hx * 1.3 + 100) + Math.floor(hz * 1.3 + 100)) & 1);
|
|
454
|
+
const fog = Math.exp(-Math.max(0, d - 3.5) * 0.28);
|
|
455
|
+
const shd = softShadow(hx, hy + 0.01, hz);
|
|
456
|
+
lumSum += (0.1 + 0.32 * chk) * (0.2 + 0.8 * shd) * fog; kind += 0; hits++;
|
|
457
|
+
} else {
|
|
458
|
+
const e = 0.0015;
|
|
459
|
+
let nx = sdTorus(hx + e, hy, hz) - sdTorus(hx - e, hy, hz), ny = sdTorus(hx, hy + e, hz) - sdTorus(hx, hy - e, hz), nz2 = sdTorus(hx, hy, hz + e) - sdTorus(hx, hy, hz - e);
|
|
460
|
+
const nl = len3(nx, ny, nz2); nx /= nl; ny /= nl; nz2 /= nl;
|
|
461
|
+
const diff = Math.max(0, nx * Lx + ny * Ly + nz2 * Lz);
|
|
462
|
+
// blinn spec
|
|
463
|
+
let hx2 = Lx - dx, hy2 = Ly - dy, hz2 = Lz - dz; const hl = len3(hx2, hy2, hz2); hx2 /= hl; hy2 /= hl; hz2 /= hl;
|
|
464
|
+
const spec = Math.pow(Math.max(0, nx * hx2 + ny * hy2 + nz2 * hz2), 40);
|
|
465
|
+
const rim = Math.pow(1 - Math.abs(nx * dx + ny * dy + nz2 * dz), 3) * 0.25;
|
|
466
|
+
lumSum += H.clamp(0.12 + diff * 0.78 + spec * 0.6 + rim); kind += 1; hits++;
|
|
467
|
+
specSum += spec;
|
|
468
|
+
const [ox, oy, oz] = rot(hx, hy, hz); angSum += Math.atan2(oz, ox); depth += d;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (!hits) continue;
|
|
472
|
+
const cover = hits / 4, lum = (lumSum / hits) * (0.55 + 0.45 * cover);
|
|
473
|
+
if (kind >= 2) { // torus
|
|
474
|
+
const idx = Math.max(1, Math.min(RAMP.length - 1, Math.round(lum * (RAMP.length - 1))));
|
|
475
|
+
const ang = angSum / kind;
|
|
476
|
+
const hue = 245 + 55 * Math.sin(ang + t * 0.6); // cyan -> violet band around the ring
|
|
477
|
+
const light = 18 + lum * 62 + (specSum / kind) * 30;
|
|
478
|
+
set(c, r, RAMP[idx], hsl(hue + lum * 20, 90, Math.min(96, light)));
|
|
479
|
+
} else { // floor
|
|
480
|
+
const idx = Math.min(FLOOR_RAMP.length - 1, Math.round(lum * 2.2 * (FLOOR_RAMP.length - 1)));
|
|
481
|
+
if (idx > 0) set(c, r, FLOOR_RAMP[idx], hsl(290 + lum * 40, 85, 10 + lum * 95));
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// bright raster row while the torus is being scanned in
|
|
486
|
+
if (scanRow <= r1) for (let c = Math.max(0, c0 + 8); c < Math.min(cols, c1 - 8); c++) if ((c + scanRow) % 2 === 0) set(c, scanRow, '▄', hsl(190, 100, 80));
|
|
487
|
+
|
|
488
|
+
// ---------- 3. figlet-style block title + box-drawn subtitle + nfo panel ----------
|
|
489
|
+
const putStr = (c, r, s, col) => [...s].forEach((ch, i) => set(c + i, r, ch, col));
|
|
490
|
+
const big = 'TOKENS';
|
|
491
|
+
const tl = H.layer(64, 10), tg = tl.getContext('2d', { willReadFrequently: true });
|
|
492
|
+
tg.font = '8px "Press Start 2P"'; tg.textBaseline = 'top'; tg.fillStyle = '#fff'; tg.fillText(big, 0, 1);
|
|
493
|
+
const td = tg.getImageData(0, 0, 64, 10).data;
|
|
494
|
+
const on = (x, y) => x >= 0 && y >= 0 && x < 64 && y < 10 && td[(y * 64 + x) * 4 + 3] > 120;
|
|
495
|
+
const bx = 4, by = 3;
|
|
496
|
+
const reveal = Math.floor(H.clamp((t - 0.2) / 1.2) * 52);
|
|
497
|
+
for (let y = 0; y < 10; y++) for (let x = 0; x < 52; x++) {
|
|
498
|
+
if (x > reveal) continue;
|
|
499
|
+
if (on(x, y)) {
|
|
500
|
+
const k = y / 8, hue = 48 - k * 70;
|
|
501
|
+
set(bx + x, by + y, k < 0.55 ? '█' : '▓', hsl((hue + 360) % 360, 100, 62 - k * 10));
|
|
502
|
+
} else if (on(x - 1, y - 1)) set(bx + x, by + y, '░', hsl(300, 80, 32));
|
|
503
|
+
}
|
|
504
|
+
const sub = 'ALL THE WAY DOWN';
|
|
505
|
+
const sw = 50, sy = by + 11;
|
|
506
|
+
const frameCol = hsl(185, 90, 55);
|
|
507
|
+
if (t >= 0.9) {
|
|
508
|
+
putStr(bx, sy, '╔' + '═'.repeat(sw - 2) + '╗', frameCol);
|
|
509
|
+
putStr(bx, sy + 1, '║' + ' '.repeat(sw - 2) + '║', frameCol);
|
|
510
|
+
putStr(bx, sy + 2, '╚' + '═'.repeat(sw - 2) + '╝', frameCol);
|
|
511
|
+
const typed = Math.floor(H.clamp((t - 1.0) / 1.0) * sub.length);
|
|
512
|
+
const subTxt = sub.split('').join(' ');
|
|
513
|
+
const shownTxt = subTxt.slice(0, typed * 2);
|
|
514
|
+
putStr(bx + 2, sy + 1, '▒░', hsl(330, 100, 60)); putStr(bx + sw - 4, sy + 1, '░▒', hsl(330, 100, 60));
|
|
515
|
+
putStr(bx + 9, sy + 1, shownTxt, '#ffffff');
|
|
516
|
+
if (Math.floor(t * 2.5) % 2 || typed < sub.length) set(bx + 9 + shownTxt.length, sy + 1, '█', '#ffffff');
|
|
517
|
+
putStr(bx + 1, sy + 3, 'a 4k intro · party release · 1996', hsl(48, 60, 40));
|
|
518
|
+
}
|
|
519
|
+
if (t >= 1.6) {
|
|
520
|
+
const pad = (s2, n) => (s2 + ' '.repeat(n)).slice(0, n);
|
|
521
|
+
const info = ['obj .......... torus', 'ramp .,-~:;=!*#$@', 'grid ....... ' + cols + 'x' + rows, 'frame ......... ' + String(Math.floor(t * 60)).padStart(4, '0'), 'shade ..... lambert+spec'];
|
|
522
|
+
putStr(bx, sy + 6, '┌─[ RENDER ]' + '─'.repeat(17) + '┐', hsl(185, 90, 40));
|
|
523
|
+
const infoN = Math.floor((t - 1.6) / 0.08);
|
|
524
|
+
info.forEach((s2, i) => { if (i < infoN) putStr(bx, sy + 7 + i, '│ ' + pad(s2, 26) + ' │', hsl(185, 60, 52)); else if (infoN >= 0) putStr(bx, sy + 7 + i, '│' + ' '.repeat(28) + '│', hsl(185, 90, 40)); });
|
|
525
|
+
putStr(bx, sy + 7 + info.length, '└' + '─'.repeat(28) + '┘', hsl(185, 90, 40));
|
|
526
|
+
set(bx + 1, sy + 9 + info.length, '|/-\\'[Math.floor(t * 10) % 4], hsl(48, 100, 62)); putStr(bx + 3, sy + 9 + info.length, 'raymarching...', hsl(48, 50, 45));
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// ---------- 4. copper bars behind the scroller ----------
|
|
530
|
+
const scrRow = rows - 6;
|
|
531
|
+
for (let k = -3; k <= 3; k++) {
|
|
532
|
+
if (Math.abs(k) > (t - 2.0) / 0.07) continue;
|
|
533
|
+
const rr = scrRow + k, li = 1 - Math.abs(k) / 3.6;
|
|
534
|
+
for (let c = 0; c < cols; c++) {
|
|
535
|
+
if (grid[rr * cols + c]) continue;
|
|
536
|
+
const hue = 280 + 40 * Math.sin(t + k * 0.5);
|
|
537
|
+
set(c, rr, k === 0 ? '═' : '─', hsl(hue, 90, 6 + li * 22));
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// ---------- 5. draw the grid ----------
|
|
542
|
+
ctx.font = '600 12px "IBM Plex Mono"'; ctx.textBaseline = 'top';
|
|
543
|
+
const glyphs = H.layer(W, H_), gx = glyphs.getContext('2d');
|
|
544
|
+
gx.font = ctx.font; gx.textBaseline = 'top';
|
|
545
|
+
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
|
|
546
|
+
const g = grid[r * cols + c]; if (!g || g[0] === ' ') continue;
|
|
547
|
+
if (!cellGlyph(gx, g[0], c * CW, r * CH, g[1])) { gx.fillStyle = g[1]; gx.fillText(g[0], c * CW, r * CH); }
|
|
548
|
+
}
|
|
549
|
+
// phosphor-ish glow: blurred additive copy, then crisp
|
|
550
|
+
ctx.save(); ctx.globalCompositeOperation = 'lighter'; ctx.globalAlpha = 0.85; ctx.filter = 'blur(6px)'; ctx.drawImage(glyphs, 0, 0); ctx.restore();
|
|
551
|
+
ctx.drawImage(glyphs, 0, 0);
|
|
552
|
+
|
|
553
|
+
// ---------- 6. sine scroller (big, rainbow, per-letter) ----------
|
|
554
|
+
const msg = '*** GREETINGS FROM LATENT SPACE *** TOKENS ALL THE WAY DOWN *** ';
|
|
555
|
+
ctx.font = '700 22px "IBM Plex Mono"';
|
|
556
|
+
const sp = 16, off = (t - 2.1) * 260 - W;
|
|
557
|
+
ctx.save();
|
|
558
|
+
for (let i = 0; i < msg.length; i++) {
|
|
559
|
+
const x = i * sp - off + 20; if (x < -20 || x > W + 20) continue;
|
|
560
|
+
const ch = msg[i % msg.length]; if (ch === ' ') continue;
|
|
561
|
+
const y = scrRow * CH - 6 + Math.sin(x * 0.012 + t * 3) * 18;
|
|
562
|
+
const hue = (x * 0.4 + t * 120) % 360;
|
|
563
|
+
ctx.fillStyle = hsl(hue, 100, 22); ctx.fillText(ch, x + 2, y + 3);
|
|
564
|
+
ctx.shadowColor = hsl(hue, 100, 60); ctx.shadowBlur = 10;
|
|
565
|
+
ctx.fillStyle = hsl(hue, 100, 66); ctx.fillText(ch, x, y);
|
|
566
|
+
ctx.shadowBlur = 0;
|
|
567
|
+
}
|
|
568
|
+
ctx.restore();
|
|
569
|
+
|
|
570
|
+
crtFinish(ctx, glyphs, W, H_);
|
|
571
|
+
H.vignette(ctx, W, H_, 0.55);
|
|
572
|
+
},
|
|
573
|
+
});
|
|
574
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 82,
|
|
3
|
+
"name": "ASCII Demoscene",
|
|
4
|
+
"nameZh": "ASCII 字符演示艺术",
|
|
5
|
+
"family": "Retro Digital",
|
|
6
|
+
"familyZh": "复古数字",
|
|
7
|
+
"description": "A ray-marched 3D torus rasterised into a strict monospace character grid via a luminance ramp, colour-coded like a 90s demoscene intro: box-drawn title panel, plasma backdrop, copper bars and a sine scroller.",
|
|
8
|
+
"motionNotes": "Motion: Like a demo intro booting: plasma thickens in, the spinning torus is rastered into characters top-to-bottom behind a bright scan row, the block title and nfo panel print, copper bars open and a rainbow sine-scroller glides in from the right.",
|
|
9
|
+
"explainerNotes": "Explainer: One long ASCII document that the terminal scrolls through row by row: figlet block-letter question, labelled ASCII cat/dog cards stepping along a box-drawing arrow into a MODEL box, a reverse-video GUESS/CHECK/ADJUST loop with a red error path, and block-character bar charts with figlet counters.",
|
|
10
|
+
"code": "code.js",
|
|
11
|
+
"registeredAs": "ascii-render",
|
|
12
|
+
"source": "https://www.futurepedia.io/resources/ai-style-atlas/view"
|
|
13
|
+
}
|