@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,73 @@
|
|
|
1
|
+
# Reading a style
|
|
2
|
+
|
|
3
|
+
Once the person has picked, the style has to become decisions: what is drawn, in what order, in what material, and
|
|
4
|
+
how each thing changes. Read it in four layers — cover, words, code, timing — and write down what you took from each.
|
|
5
|
+
|
|
6
|
+
## 1. The cover
|
|
7
|
+
|
|
8
|
+
Open `assets/atlas/styles/<folder>/poster.jpg` and look at it. Write down, in your own words: the palette (three to
|
|
9
|
+
five real colours, not “warm”), the composition (where the eye lands, what is behind what), the type (is the title
|
|
10
|
+
drawn, set, lettered, cut out?), the material (paper, glass, ink, pixels), the line (edge, weight, wobble), and the
|
|
11
|
+
light (flat, raking, glowing). These are the style's invariants: the film keeps them whatever its subject.
|
|
12
|
+
|
|
13
|
+
## 2. The words
|
|
14
|
+
|
|
15
|
+
`style.json` says the style twice — `description` for the look, `motionNotes` for how it moves, `explainerNotes` for
|
|
16
|
+
how it explains. Read all three. `explainerNotes` is the most useful: it names the moves that carry an argument in
|
|
17
|
+
this style (a camera pull that turns examples into a galaxy, a wipe that is a planet crossing, a counter that counts).
|
|
18
|
+
|
|
19
|
+
## 3. The code
|
|
20
|
+
|
|
21
|
+
`code.js` is the reference animation: `registerStyle({ draw(ctx, W, H, t) })`, a pure function of time. Read it for
|
|
22
|
+
mechanism, in this order:
|
|
23
|
+
|
|
24
|
+
1. **What is drawn once and kept** — the background, the paper texture, the finishing pass (`putImageData`,
|
|
25
|
+
`globalCompositeOperation`, a grain overlay). That is the look's body.
|
|
26
|
+
2. **What is a function of `t`** — positions, scales, opacities, `smoothstep(e0, e1, t)`, phases, `Math.sin(t * k)`.
|
|
27
|
+
Each of those is a beat, and the numbers are its start and end.
|
|
28
|
+
3. **The objects** — how a shape is built (`deform`, `circlePts`, a grid, a path) and what its parameters mean. This
|
|
29
|
+
is what makes a watercolour wash different from a flat shape with a soft edge.
|
|
30
|
+
4. **The helpers** — `lib/harness.js` (seeded `rng`, `makeNoise`, `ease`, canvas helpers) and `lib/sound.js`. They are
|
|
31
|
+
shared by all 86; read each once. Seeded randomness is why the same frame looks the same twice: keep that, it is
|
|
32
|
+
what lets a film be looked at and fixed.
|
|
33
|
+
|
|
34
|
+
Long files: read in pieces. Never claim you read a file that a tool cut in half.
|
|
35
|
+
|
|
36
|
+
Do **not** execute the archive's files. Read them. The one thing to port is the technique.
|
|
37
|
+
|
|
38
|
+
## 4. Timing, from the code rather than a video
|
|
39
|
+
|
|
40
|
+
No reference video is archived here; the time is in the code, which is the better record anyway. For the two or three
|
|
41
|
+
moves that carry the explanation, write the beat as a line:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
X: 0.0–1.2 s washes flood in from the pencil outline, edges darken as they dry
|
|
45
|
+
X: 1.2–2.6 s the camera pans along one long sheet; the counter brushes itself in
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If a move's timing cannot be told from the code, it cannot be claimed in the film either — decide it yourself, and say
|
|
49
|
+
you did.
|
|
50
|
+
|
|
51
|
+
## Then the style constraints
|
|
52
|
+
|
|
53
|
+
Write five lines before any page is written:
|
|
54
|
+
|
|
55
|
+
- **3–5 invariants** — the things whose absence makes it another style (paper edge darkening; claret-only highlight;
|
|
56
|
+
hairline grid; small-caps source line).
|
|
57
|
+
- **2–3 motion rules** — how things enter and leave, what eases, what stays still (a newspaper page scrolls, it does
|
|
58
|
+
not zoom).
|
|
59
|
+
- **Type** — the hierarchy and whether the letters are drawn, set or lettered; for Chinese, a face with real Chinese
|
|
60
|
+
glyphs, never a Latin-only face asked to fake them.
|
|
61
|
+
- **What carries the argument** — the one mechanism that will explain the topic (a line drawing itself; a wash
|
|
62
|
+
flooding a shape; a counter).
|
|
63
|
+
- **What not to bring** — the reference's subject. A watercolour cover of a lightbulb does not mean the film gets a
|
|
64
|
+
lightbulb; the person's topic decides every object.
|
|
65
|
+
|
|
66
|
+
## Porting to an AICUT page
|
|
67
|
+
|
|
68
|
+
- The page is `frame(t)`, the archive is `draw(ctx, W, H, t)`; the same clock, so beats move over unchanged.
|
|
69
|
+
- AICUT pages draw with DOM, SVG, CSS and canvas as you prefer. Canvas work (noise, texture, granulation) ports most
|
|
70
|
+
directly; type is better set as DOM text so it stays crisp and editable.
|
|
71
|
+
- The film's stage is fixed; the archive's `W, H` become the stage's size. Keep the composition's proportions.
|
|
72
|
+
- Sound: the archive's `sound.js` is a kit, not a soundtrack. Make the film's sound from its own beats.
|
|
73
|
+
- Keep the credit: the style came from the archive; say so once, in the film's own notes or the reply, not on screen.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Three covers, one card
|
|
2
|
+
|
|
3
|
+
The first turn is a decision about direction. Everything here is about making that decision easy to take: three
|
|
4
|
+
pictures the person can actually see, three names, one click.
|
|
5
|
+
|
|
6
|
+
## Choosing the three
|
|
7
|
+
|
|
8
|
+
Read `references/style-index.json` — all 86 rows — before choosing, and open the poster and `style.json` of each
|
|
9
|
+
candidate. Three that are near each other in family are three ways of saying the same thing; three that differ in
|
|
10
|
+
**how they explain** are a real choice:
|
|
11
|
+
|
|
12
|
+
- one whose mechanism is drawing (whiteboard, Manim, isotype, blueprint, transit map);
|
|
13
|
+
- one whose mechanism is material or craft (watercolour, paper cut, clay, felt, cross-stitch, mosaic);
|
|
14
|
+
- one whose mechanism is graphic or photographic (halftone, risograph, editorial chart, blueprint negative, neon).
|
|
15
|
+
|
|
16
|
+
A topic about a process usually wants the first. A topic about a feeling or a person wants the second. A topic about
|
|
17
|
+
numbers wants the third. Say why each fits *this* topic in one sentence — not what the style is, but what it would do
|
|
18
|
+
for this film.
|
|
19
|
+
|
|
20
|
+
## Getting the covers into the project
|
|
21
|
+
|
|
22
|
+
The card draws pictures from the project's own folder, so copy the three covers in first. From the project folder:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
node .pi/skills/aicut-motion/scripts/atlas.mjs --pick 32,26,2
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
It prints the three with the path each will be given as `picture` (`assets/style-pick/032-sumi-e-ink-wash.jpg` and so
|
|
29
|
+
on). Ids may be numbers, folders (`032-sumi-e-ink-wash`) or a unique part of a name; a number that names nothing stops
|
|
30
|
+
with an error rather than picking a neighbour. `--into pictures/picks` copies them elsewhere and prints those paths.
|
|
31
|
+
|
|
32
|
+
If the project has no copy of this skill under `.pi/skills` — the skill was read from the app's own folder — run the
|
|
33
|
+
same script by that path; what matters is where the covers land, not where the script is.
|
|
34
|
+
|
|
35
|
+
## The ask
|
|
36
|
+
|
|
37
|
+
One question, two to five options, the recommended one first, the three labels short enough to read on a card:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
ask({ questions: [{
|
|
41
|
+
question: '这次片子想用哪一种视觉风格?选定后我先做一段约 20 秒的样片。',
|
|
42
|
+
header: '视觉方向',
|
|
43
|
+
options: [
|
|
44
|
+
{ label: 'A · 报刊数据图表 Editorial Chart', description: '为什么它适合这个选题', picture: 'assets/style-pick/026-editorial-chart.jpg' },
|
|
45
|
+
{ label: 'B · 水墨晕染 Sumi-e Ink Wash', description: '…', picture: 'assets/style-pick/032-sumi-e-ink-wash.jpg' },
|
|
46
|
+
{ label: 'C · 水彩晕染 Watercolor Wash', description: '…', picture: 'assets/style-pick/002-watercolor-wash.jpg' },
|
|
47
|
+
],
|
|
48
|
+
}]})
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- Label, `description` and `picture` must describe **the same style** — a card whose picture and name disagree is
|
|
52
|
+
worse than no card.
|
|
53
|
+
- `picture` is a path inside the project, forward slashes, no leading `/`, no `file://`, no CDN.
|
|
54
|
+
- The card is the answer; do not also ask the same question in words in the same turn.
|
|
55
|
+
|
|
56
|
+
Before the card, one or two lines are enough: what the person should understand by the end, and that the pictures are
|
|
57
|
+
the styles' own covers — the subject in them is not their topic, and the sample will be.
|
|
58
|
+
|
|
59
|
+
## After the card
|
|
60
|
+
|
|
61
|
+
The answer comes back as the picked label (or the person's own words). Record the style id with it. Then go straight to
|
|
62
|
+
the sample: no second card, no second shortlist, no generated images.
|
|
63
|
+
|
|
64
|
+
If the person names a style that was not among the three — from an earlier message, or by name — take it. Match by
|
|
65
|
+
`nameZh`, `name`, id or folder; when two match, ask which, in words.
|
|
66
|
+
|
|
67
|
+
## Without the picture card
|
|
68
|
+
|
|
69
|
+
Some hosts' question tools take text only. Then the three covers still have to be seen: give each option's real path
|
|
70
|
+
in the reply (`assets/style-pick/026-editorial-chart.jpg`) beside its name, and ask in words. Never say “above” or
|
|
71
|
+
“如图” about a picture the person cannot see, and never describe a cover you did not open.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>86 archived styles — preview</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root{
|
|
9
|
+
--ink:#0d0d0f; --card:#16161a; --line:#2c2c33; --tx:#ecebe7; --tx2:#a5a39d; --tx3:#6e6c67; --hot:#e05a3d;
|
|
10
|
+
--sans:"Inter","HarmonyOS Sans SC","PingFang SC","Microsoft YaHei",system-ui,sans-serif;
|
|
11
|
+
--mono:"JetBrains Mono","SF Mono",Consolas,monospace;
|
|
12
|
+
}
|
|
13
|
+
*{box-sizing:border-box}
|
|
14
|
+
body{margin:0;background:var(--ink);color:var(--tx);font-family:var(--sans);font-size:14px}
|
|
15
|
+
header{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding:16px 20px;border-bottom:1px solid var(--line)}
|
|
16
|
+
h1{margin:0;font-size:15px;font-weight:500;letter-spacing:-.01em}
|
|
17
|
+
.sub{font-family:var(--mono);font-size:11px;color:var(--tx3);letter-spacing:.06em}
|
|
18
|
+
.grow{flex:1}
|
|
19
|
+
select,input[type=range],button{font-family:inherit}
|
|
20
|
+
select{background:var(--card);color:var(--tx);border:1px solid var(--line);border-radius:3px;padding:7px 10px;font-size:13px;max-width:340px}
|
|
21
|
+
button{background:var(--card);color:var(--tx2);border:1px solid var(--line);border-radius:3px;padding:7px 11px;font-size:12px;cursor:pointer;line-height:1.2}
|
|
22
|
+
button:hover{color:var(--tx);border-color:var(--tx3)}
|
|
23
|
+
button:disabled{opacity:.4;cursor:default}
|
|
24
|
+
main{max-width:1180px;margin:0 auto;padding:20px}
|
|
25
|
+
canvas{width:100%;height:auto;display:block;background:#111;border:1px solid var(--line);border-radius:3px}
|
|
26
|
+
.transport{display:flex;align-items:center;gap:12px;margin-top:12px}
|
|
27
|
+
input[type=range]{flex:1;accent-color:var(--hot);height:18px}
|
|
28
|
+
.clock{font-family:var(--mono);font-size:11.5px;color:var(--tx3);min-width:96px;text-align:right}
|
|
29
|
+
.cols{display:grid;grid-template-columns:1.35fr 1fr;gap:22px;margin-top:18px}
|
|
30
|
+
@media (max-width:860px){.cols{grid-template-columns:1fr}}
|
|
31
|
+
.cols p{margin:0 0 10px;font-size:13px;line-height:1.65;color:var(--tx2)}
|
|
32
|
+
.cols b{display:block;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;color:var(--hot);margin-bottom:3px;font-weight:500}
|
|
33
|
+
.note{font-size:12px;color:var(--tx3);line-height:1.6;border-top:1px solid var(--line);padding-top:12px;margin-top:4px}
|
|
34
|
+
code{font-family:var(--mono);font-size:11.5px;color:#cfcdc7;background:rgba(255,255,255,.055);padding:1px 5px;border-radius:2px}
|
|
35
|
+
.meta{font-family:var(--mono);font-size:10.5px;color:#4e4e57;word-break:break-all;margin-top:8px}
|
|
36
|
+
</style>
|
|
37
|
+
</head>
|
|
38
|
+
<body>
|
|
39
|
+
<header>
|
|
40
|
+
<h1>86 archived styles</h1>
|
|
41
|
+
<span class="sub">harness.js + code.js + a t</span>
|
|
42
|
+
<div class="grow"></div>
|
|
43
|
+
<button id="prev" title="上一种(←)">←</button>
|
|
44
|
+
<select id="pick"></select>
|
|
45
|
+
<button id="next" title="下一种(→)">→</button>
|
|
46
|
+
<button id="play" title="播放 / 暂停(空格)">暂停</button>
|
|
47
|
+
</header>
|
|
48
|
+
|
|
49
|
+
<main>
|
|
50
|
+
<canvas id="c" width="1920" height="1080"></canvas>
|
|
51
|
+
<div class="transport">
|
|
52
|
+
<input id="scrub" type="range" min="0" max="1000" value="0" aria-label="时间">
|
|
53
|
+
<span class="clock" id="clock">0.00 / 6.00 s</span>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div class="cols">
|
|
57
|
+
<div>
|
|
58
|
+
<p><b>看</b><span id="desc">—</span></p>
|
|
59
|
+
<p><b>动</b><span id="motion">—</span></p>
|
|
60
|
+
</div>
|
|
61
|
+
<div>
|
|
62
|
+
<p><b>讲</b><span id="who">—</span></p>
|
|
63
|
+
<p class="note">这个页面只是档案的预览壳:它加载 <code>lib/harness.js</code> 和某一套的 <code>code.js</code>,然后把 <code>t</code> 递进去。
|
|
64
|
+
片子要的是这种时间结构,不是这个文件本身——把它移植成 AICUT 页面里的 <code>frame(t)</code>,而不是嵌进来。</p>
|
|
65
|
+
<div class="meta" id="meta"></div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</main>
|
|
69
|
+
|
|
70
|
+
<script src="../assets/atlas/lib/harness.js"></script>
|
|
71
|
+
<script type="application/json" id="fallback">[[1,"Flat-Vector Science","扁平矢量科普","Popular Explainer Looks","经典讲解","001-flat-vector-science"],[2,"Watercolor Wash","水彩晕染","Painterly","绘画质感","002-watercolor-wash"],[3,"Shadow Puppet Theatre","皮影剧场","Paper & Craft","纸艺与手工","003-shadow-puppet-theatre"],[4,"Whiteboard Explainer","白板讲解","Hand-Drawn","手绘","004-whiteboard-explainer"],[5,"Psychedelic Poster","迷幻海报","Cosmic & Psychedelic","宇宙与迷幻","005-psychedelic-poster"],[6,"Tech Glow Explainer","科技辉光讲解","Popular Explainer Looks","经典讲解","006-tech-glow-explainer"],[7,"Papercraft Models","纸艺模型","Popular Explainer Looks","经典讲解","007-papercraft-models"],[8,"1940s Film Noir","1940年代黑色电影","Light & Imaging","光影与成像","008-1940s-film-noir"],[9,"Manim-Style Math","Manim 数学动画","Popular Explainer Looks","经典讲解","009-manim-style-math"],[10,"Illuminated Manuscript","彩饰手抄本","Illustration","插画","010-illuminated-manuscript"],[11,"Editorial Essay Collage","社论拼贴","Popular Explainer Looks","经典讲解","011-editorial-essay-collage"],[12,"Bioluminescent Deep Sea","深海生物荧光","Light & Imaging","光影与成像","012-bioluminescent-deep-sea"],[13,"Product Launch Reveal","产品发布揭幕","Popular Explainer Looks","经典讲解","013-product-launch-reveal"],[14,"Halftone Pop Panel","半色调波普","Print","印刷质感","014-halftone-pop-panel"],[15,"Isometric Pastel","等距粉彩","Dimensional","立体空间","015-isometric-pastel"],[16,"Oscilloscope Vector Art","示波器矢量艺术","Retro Digital","复古数字","016-oscilloscope-vector-art"],[17,"Risograph Zine","孔版印刷小志","Print","印刷质感","017-risograph-zine"],[18,"Claymation Set","黏土定格布景","Paper & Craft","纸艺与手工","018-claymation-set"],[19,"Neon Sign at Night","夜色霓虹招牌","Light & Imaging","光影与成像","019-neon-sign-at-night"],[20,"Kawaii Anime","可爱动漫","Popular Explainer Looks","经典讲解","020-kawaii-anime"],[21,"Ukiyo-e Woodblock","浮世绘木版画","Art & Design Movements","艺术与设计流派","021-ukiyo-e-woodblock"],[22,"16-Bit Pixel Odyssey","16位像素奇旅","Retro Digital","复古数字","022-16-bit-pixel-odyssey"],[23,"Chalkboard Lesson","黑板课堂","Hand-Drawn","手绘","023-chalkboard-lesson"],[24,"Cut-Paper Diorama","剪纸立体景","Paper & Craft","纸艺与手工","024-cut-paper-diorama"],[25,"Cathedral Glass","教堂彩绘玻璃","Painterly","绘画质感","025-cathedral-glass"],[26,"Editorial Chart","报刊数据图表","Data & Information","数据与信息","026-editorial-chart"],[27,"Synthwave Outrun","合成波疾驰","Retro UI & Neon","复古界面与霓虹","027-synthwave-outrun"],[28,"Origami Studio","折纸工作室","Paper & Craft","纸艺与手工","028-origami-studio"],[29,"Linocut Relief Print","油毡浮雕版画","Print","印刷质感","029-linocut-relief-print"],[30,"Holographic Foil Card","全息箔卡片","Light & Imaging","光影与成像","030-holographic-foil-card"],[31,"Voxel Diorama","体素微缩景观","Dimensional","立体空间","031-voxel-diorama"],[32,"Sumi-e Ink Wash","水墨晕染","Painterly","绘画质感","032-sumi-e-ink-wash"],[33,"Etch A Sketch Toy","旋钮绘图玩具","Hand-Drawn","手绘","033-etch-a-sketch-toy"],[34,"Cosmic Star Chart","宇宙星图","Cosmic & Psychedelic","宇宙与迷幻","034-cosmic-star-chart"],[35,"Punk Zine Collage","朋克拼贴小志","Paper & Craft","纸艺与手工","035-punk-zine-collage"],[36,"Thermal Camera","热成像","Light & Imaging","光影与成像","036-thermal-camera"],[37,"Engineering Blueprint","工程蓝图","Hand-Drawn","手绘","037-engineering-blueprint"],[38,"Impasto Night","厚涂夜景","Painterly","绘画质感","038-impasto-night"],[39,"Win95 Desktop","Windows 95 桌面","Retro UI & Neon","复古界面与霓虹","039-win95-desktop"],[40,"Low-Poly Faceted","低多边形切面","Dimensional","立体空间","040-low-poly-faceted"],[41,"Manga Page","漫画分镜页","Illustration","插画","041-manga-page"],[42,"Wood Type Letterpress","木活字凸版印刷","Print","印刷质感","042-wood-type-letterpress"],[43,"Light Painting","光绘","Light & Imaging","光影与成像","043-light-painting"],[44,"Felt & Patchwork","毛毡与拼布","Paper & Craft","纸艺与手工","044-felt-patchwork"],[45,"Phosphor Terminal","荧光终端","Retro Digital","复古数字","045-phosphor-terminal"],[46,"Glassmorphism UI","毛玻璃界面","Dimensional","立体空间","046-glassmorphism-ui"],[47,"Tarot Card","塔罗牌","Illustration","插画","047-tarot-card"],[48,"Transit Map","公共交通线路图","Data & Information","数据与信息","048-transit-map"],[49,"Gouache Travel Poster","水粉旅行海报","Painterly","绘画质感","049-gouache-travel-poster"],[50,"Napkin Sketch","餐巾纸草图","Hand-Drawn","手绘","050-napkin-sketch"],[51,"Art Deco Foil","装饰艺术烫箔","Art & Design Movements","艺术与设计流派","051-art-deco-foil"],[52,"Radiograph on Lightbox","灯箱X光片","Light & Imaging","光影与成像","052-radiograph-on-lightbox"],[53,"Vaporwave","蒸汽波","Retro UI & Neon","复古界面与霓虹","053-vaporwave"],[54,"Ebru Paper Marbling","土耳其水拓画","Generative & Type","生成艺术与字体","054-ebru-paper-marbling"],[55,"ISOTYPE Pictograms","ISOTYPE 图形符号","Data & Information","数据与信息","055-isotype-pictograms"],[56,"Soft 3D Clay","柔软3D黏土","Dimensional","立体空间","056-soft-3d-clay"],[57,"Cross-Stitch Sampler","十字绣样本","Paper & Craft","纸艺与手工","057-cross-stitch-sampler"],[58,"Constructivist Propaganda","构成主义宣传画","Art & Design Movements","艺术与设计流派","058-constructivist-propaganda"],[59,"Pocket Monochrome","掌机单色像素","Retro Digital","复古数字","059-pocket-monochrome"],[60,"Botanical Plate","植物学图谱","Illustration","插画","060-botanical-plate"],[61,"Kinetic Type","动态字体","Generative & Type","生成艺术与字体","061-kinetic-type"],[62,"Byzantine Mosaic","拜占庭马赛克","Illustration","插画","062-byzantine-mosaic"],[63,"Y2K Liquid Chrome","Y2K 液态铬","Retro UI & Neon","复古界面与霓虹","063-y2k-liquid-chrome"],[64,"Sticky-Note Wall","便利贴墙","Illustration","插画","064-sticky-note-wall"],[65,"Vintage Newsprint","复古新闻纸","Print","印刷质感","065-vintage-newsprint"],[66,"Hidden-Line Wireframe","隐藏线框图","Dimensional","立体空间","066-hidden-line-wireframe"],[67,"Memphis Group","孟菲斯设计","Art & Design Movements","艺术与设计流派","067-memphis-group"],[68,"Ballpoint Notebook","圆珠笔笔记","Hand-Drawn","手绘","068-ballpoint-notebook"],[69,"Op Art Sphere","欧普艺术球体","Generative & Type","生成艺术与字体","069-op-art-sphere"],[70,"Topographic Survey","地形测绘","Data & Information","数据与信息","070-topographic-survey"],[71,"Pointillist Afternoon","点彩午后","Painterly","绘画质感","071-pointillist-afternoon"],[72,"Vector Arcade 1980","1980年代矢量街机","Retro Digital","复古数字","072-vector-arcade-1980"],[73,"Patent Drawing","专利图纸","Illustration","插画","073-patent-drawing"],[74,"Bauhaus Poster","包豪斯海报","Art & Design Movements","艺术与设计流派","074-bauhaus-poster"],[75,"Bitmap Paint Doodle","位图画板涂鸦","Retro UI & Neon","复古界面与霓虹","075-bitmap-paint-doodle"],[76,"Nail & Thread String Art","钉线绕线艺术","Generative & Type","生成艺术与字体","076-nail-thread-string-art"],[77,"Ridgeline","山脊线图","Data & Information","数据与信息","077-ridgeline"],[78,"Sketchbook Graphite","石墨素描本","Hand-Drawn","手绘","078-sketchbook-graphite"],[79,"Teletext Page","图文电视页","Retro UI & Neon","复古界面与霓虹","079-teletext-page"],[80,"Silkscreen Grid","丝网印刷网格","Print","印刷质感","080-silkscreen-grid"],[81,"Guilloché Security Print","玑镂防伪纹样","Generative & Type","生成艺术与字体","081-guilloch-security-print"],[82,"ASCII Demoscene","ASCII 字符演示艺术","Retro Digital","复古数字","082-ascii-demoscene"],[83,"International Typographic Style","国际主义字体设计","Art & Design Movements","艺术与设计流派","083-international-typographic-style"],[84,"Flow Field","流场","Data & Information","数据与信息","084-flow-field"],[85,"MacPaint 1984","MacPaint 1984 画板","Retro Digital","复古数字","085-macpaint-1984"],[86,"Multi-scale Truchet","多尺度特鲁歇拼砖","Generative & Type","生成艺术与字体","086-multi-scale-truchet"]]</script>
|
|
72
|
+
<script>
|
|
73
|
+
(function () {
|
|
74
|
+
var BASE = '../assets/atlas';
|
|
75
|
+
var FALLBACK = JSON.parse(document.getElementById('fallback').textContent).map(function (r) {
|
|
76
|
+
return { id: r[0], name: r[1], nameZh: r[2], family: r[3], familyZh: r[4], folder: r[5] };
|
|
77
|
+
});
|
|
78
|
+
var el = {
|
|
79
|
+
pick: document.getElementById('pick'), canvas: document.getElementById('c'),
|
|
80
|
+
play: document.getElementById('play'), scrub: document.getElementById('scrub'),
|
|
81
|
+
clock: document.getElementById('clock'), desc: document.getElementById('desc'),
|
|
82
|
+
motion: document.getElementById('motion'), who: document.getElementById('who'), meta: document.getElementById('meta')
|
|
83
|
+
};
|
|
84
|
+
var ctx = el.canvas.getContext('2d');
|
|
85
|
+
var styles = FALLBACK, style = null, raf = 0, playing = true, base = 0, tNow = 0, loading = false;
|
|
86
|
+
|
|
87
|
+
function boot(list) {
|
|
88
|
+
styles = list;
|
|
89
|
+
el.pick.innerHTML = '';
|
|
90
|
+
for (var i = 0; i < styles.length; i++) {
|
|
91
|
+
var s = styles[i];
|
|
92
|
+
var label = String(s.id).padStart(3, '0') + ' · ' + s.nameZh + ' · ' + s.name;
|
|
93
|
+
el.pick.add(new Option(label, String(s.id)));
|
|
94
|
+
}
|
|
95
|
+
var want = Number(new URLSearchParams(location.search).get('id') || 26);
|
|
96
|
+
var has = styles.some(function (s) { return s.id === want; });
|
|
97
|
+
el.pick.value = String(has ? want : 1);
|
|
98
|
+
show(has ? want : 1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function show(id) {
|
|
102
|
+
var row = null;
|
|
103
|
+
for (var i = 0; i < styles.length; i++) if (styles[i].id === Number(id)) row = styles[i];
|
|
104
|
+
if (!row || loading) return;
|
|
105
|
+
loading = true;
|
|
106
|
+
cancelAnimationFrame(raf);
|
|
107
|
+
if (window.STYLES) window.STYLES.length = 0;
|
|
108
|
+
var old = document.querySelector('script[data-style]');
|
|
109
|
+
if (old) old.remove();
|
|
110
|
+
var tag = document.createElement('script');
|
|
111
|
+
tag.src = BASE + '/styles/' + row.folder + '/code.js';
|
|
112
|
+
tag.dataset.style = '1';
|
|
113
|
+
tag.onload = function () {
|
|
114
|
+
loading = false;
|
|
115
|
+
style = window.STYLES && window.STYLES[0];
|
|
116
|
+
if (!style || typeof style.draw !== 'function') {
|
|
117
|
+
el.desc.textContent = '这一套没有注册可绘制的风格(' + row.folder + ')';
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
el.desc.textContent = style.description || row.nameZh;
|
|
121
|
+
el.motion.textContent = style.motion || '—';
|
|
122
|
+
el.who.textContent = row.nameZh + ' · ' + row.name + ' · ' + row.familyZh + ' / ' + row.family;
|
|
123
|
+
el.meta.textContent = 'duration ' + style.duration + 's · ' + BASE + '/styles/' + row.folder + '/code.js';
|
|
124
|
+
history.replaceState(null, '', '?id=' + row.id);
|
|
125
|
+
base = performance.now();
|
|
126
|
+
tNow = 0;
|
|
127
|
+
playing = true;
|
|
128
|
+
el.play.textContent = '暂停';
|
|
129
|
+
draw();
|
|
130
|
+
};
|
|
131
|
+
tag.onerror = function () { loading = false; el.desc.textContent = '加载失败:' + row.folder; };
|
|
132
|
+
document.body.appendChild(tag);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function draw() {
|
|
136
|
+
cancelAnimationFrame(raf);
|
|
137
|
+
var tick = function () {
|
|
138
|
+
raf = requestAnimationFrame(tick);
|
|
139
|
+
if (!style) return;
|
|
140
|
+
if (playing) tNow = ((performance.now() - base) / 1000) % style.duration;
|
|
141
|
+
paint(style, tNow);
|
|
142
|
+
el.scrub.value = String(Math.round((tNow / style.duration) * 1000));
|
|
143
|
+
el.clock.textContent = tNow.toFixed(2) + ' / ' + style.duration.toFixed(2) + ' s';
|
|
144
|
+
};
|
|
145
|
+
tick();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function paint(s, t) {
|
|
149
|
+
ctx.save();
|
|
150
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
151
|
+
ctx.clearRect(0, 0, el.canvas.width, el.canvas.height);
|
|
152
|
+
try { s.draw(ctx, el.canvas.width, el.canvas.height, t); }
|
|
153
|
+
catch (err) { el.desc.textContent = 'draw 出错:' + err.message; playing = false; el.play.textContent = '播放'; }
|
|
154
|
+
ctx.restore();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function step(delta) {
|
|
158
|
+
var ids = styles.map(function (s) { return s.id; });
|
|
159
|
+
var at = ids.indexOf(Number(el.pick.value));
|
|
160
|
+
var next = (at + delta + ids.length) % ids.length;
|
|
161
|
+
el.pick.value = String(ids[next]);
|
|
162
|
+
show(ids[next]);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
el.pick.addEventListener('change', function () { show(el.pick.value); });
|
|
166
|
+
el.play.addEventListener('click', function () {
|
|
167
|
+
playing = !playing;
|
|
168
|
+
el.play.textContent = playing ? '暂停' : '播放';
|
|
169
|
+
base = performance.now() - tNow * 1000;
|
|
170
|
+
});
|
|
171
|
+
el.scrub.addEventListener('input', function () {
|
|
172
|
+
if (!style) return;
|
|
173
|
+
playing = false;
|
|
174
|
+
el.play.textContent = '播放';
|
|
175
|
+
tNow = (Number(el.scrub.value) / 1000) * style.duration;
|
|
176
|
+
paint(style, tNow);
|
|
177
|
+
el.clock.textContent = tNow.toFixed(2) + ' / ' + style.duration.toFixed(2) + ' s';
|
|
178
|
+
});
|
|
179
|
+
document.getElementById('prev').addEventListener('click', function () { step(-1); });
|
|
180
|
+
document.getElementById('next').addEventListener('click', function () { step(1); });
|
|
181
|
+
document.addEventListener('keydown', function (e) {
|
|
182
|
+
if (e.target.tagName === 'SELECT' || e.target.tagName === 'INPUT') return;
|
|
183
|
+
if (e.code === 'Space') { e.preventDefault(); el.play.click(); }
|
|
184
|
+
if (e.key === 'ArrowLeft') step(-1);
|
|
185
|
+
if (e.key === 'ArrowRight') step(1);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
fetch('../references/style-index.json')
|
|
189
|
+
.then(function (r) { return r.ok ? r.json() : null; })
|
|
190
|
+
.then(function (list) { boot(list && list.length ? list : FALLBACK); })
|
|
191
|
+
.catch(function () { boot(FALLBACK); });
|
|
192
|
+
})();
|
|
193
|
+
</script>
|
|
194
|
+
</body>
|
|
195
|
+
</html>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The 86 styles, as commands — so a session does not read 86 folders by hand to find one.
|
|
4
|
+
*
|
|
5
|
+
* node scripts/atlas.mjs --list every style, one line each
|
|
6
|
+
* node scripts/atlas.mjs --list --family Painterly one family only
|
|
7
|
+
* node scripts/atlas.mjs --id 26 one style: its style.json, its code, its cover
|
|
8
|
+
* node scripts/atlas.mjs --verify that all 86 are whole (poster, style.json, code)
|
|
9
|
+
* node scripts/atlas.mjs --pick 26,32,2 copy those covers into the project, for the pick card
|
|
10
|
+
* node scripts/atlas.mjs --pick 26,32,2 --into assets/style-pick
|
|
11
|
+
*
|
|
12
|
+
* `--pick` writes into `<cwd>/assets/style-pick/` by default and prints, for each, the path to give the ask card as
|
|
13
|
+
* `picture` (a path inside the project). Nothing else here writes anything.
|
|
14
|
+
*
|
|
15
|
+
* To see one play instead of reading it: open `scripts/atlas-viewer.html` in a browser (`?id=26` picks one).
|
|
16
|
+
*/
|
|
17
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync } from 'node:fs';
|
|
18
|
+
import { join, relative, resolve } from 'node:path';
|
|
19
|
+
|
|
20
|
+
const HERE = import.meta.dirname;
|
|
21
|
+
const ATLAS = resolve(HERE, '..', 'assets', 'atlas', 'styles');
|
|
22
|
+
const INDEX = resolve(HERE, '..', 'references', 'style-index.json');
|
|
23
|
+
|
|
24
|
+
/** Every style, by folder, in id order. */
|
|
25
|
+
function styles() {
|
|
26
|
+
const index = JSON.parse(readFileSync(INDEX, 'utf8'));
|
|
27
|
+
return index.map((one) => ({ ...one, at: join(ATLAS, one.folder) }));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const args = process.argv.slice(2);
|
|
31
|
+
const flag = (name) => {
|
|
32
|
+
const at = args.indexOf(name);
|
|
33
|
+
return at >= 0 ? (args[at + 1] && !args[at + 1].startsWith('--') ? args[at + 1] : true) : null;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** A style by what a person would say: 26, 026, "026-ink-wash", "ink-wash", or a unique part of either name. */
|
|
37
|
+
function find(what) {
|
|
38
|
+
const list = styles();
|
|
39
|
+
const text = String(what).trim().toLowerCase();
|
|
40
|
+
const exact = list.find((one) => String(one.id) === text.replace(/^0+(?=\d)/, '') || one.folder.toLowerCase() === text);
|
|
41
|
+
if (exact) return exact;
|
|
42
|
+
const loose = list.filter((one) => one.folder.toLowerCase().includes(text) || one.name.toLowerCase().includes(text) || one.nameZh.includes(text));
|
|
43
|
+
return loose.length === 1 ? loose[0] : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const all = styles();
|
|
47
|
+
|
|
48
|
+
if (flag('--list') || args.length === 0) {
|
|
49
|
+
const family = flag('--family');
|
|
50
|
+
const rows = family ? all.filter((one) => one.family === family || one.familyZh === family) : all;
|
|
51
|
+
console.log(`${rows.length} styles${family ? ` in ${family}` : ''}`);
|
|
52
|
+
for (const one of rows) console.log(`${String(one.id).padStart(3, '0')} ${one.nameZh} · ${one.name} [${one.familyZh}] ${one.folder}`);
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (flag('--id')) {
|
|
57
|
+
const one = find(flag('--id'));
|
|
58
|
+
if (!one) {
|
|
59
|
+
console.error(`no such style: ${flag('--id')}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
const style = JSON.parse(readFileSync(join(one.at, 'style.json'), 'utf8'));
|
|
63
|
+
console.log(JSON.stringify({
|
|
64
|
+
...style,
|
|
65
|
+
folder: one.folder,
|
|
66
|
+
poster: `assets/atlas/styles/${one.folder}/poster.jpg`,
|
|
67
|
+
code: style.code ? `assets/atlas/styles/${one.folder}/${style.code}` : null,
|
|
68
|
+
}, null, 2));
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (flag('--verify')) {
|
|
73
|
+
const missing = [];
|
|
74
|
+
for (const one of all) {
|
|
75
|
+
const style = existsSync(join(one.at, 'style.json')) ? JSON.parse(readFileSync(join(one.at, 'style.json'), 'utf8')) : null;
|
|
76
|
+
if (!style) missing.push(`${one.folder}: no style.json`);
|
|
77
|
+
else if (!existsSync(join(one.at, 'poster.jpg'))) missing.push(`${one.folder}: no poster.jpg`);
|
|
78
|
+
else if (style.code && !existsSync(join(one.at, style.code))) missing.push(`${one.folder}: no ${style.code}`);
|
|
79
|
+
}
|
|
80
|
+
const bytes = (p) => statSync(p).size;
|
|
81
|
+
const posters = all.reduce((sum, one) => sum + (existsSync(join(one.at, 'poster.jpg')) ? bytes(join(one.at, 'poster.jpg')) : 0), 0);
|
|
82
|
+
console.log(`${all.length} styles · ${Math.round(posters / 1024)} kB of covers · ${missing.length ? `${missing.length} incomplete` : 'complete'}`);
|
|
83
|
+
for (const line of missing) console.log(` ${line}`);
|
|
84
|
+
process.exit(missing.length ? 1 : 0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (flag('--pick')) {
|
|
88
|
+
const ids = String(flag('--pick')).split(',').map((one) => one.trim()).filter(Boolean);
|
|
89
|
+
const into = resolve(String(flag('--into') ?? 'assets/style-pick'));
|
|
90
|
+
const picked = [];
|
|
91
|
+
for (const id of ids) {
|
|
92
|
+
const one = find(id);
|
|
93
|
+
if (!one) {
|
|
94
|
+
console.error(`no such style: ${id}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
mkdirSync(into, { recursive: true });
|
|
98
|
+
const name = `${one.folder}.jpg`;
|
|
99
|
+
const target = join(into, name);
|
|
100
|
+
copyFileSync(join(one.at, 'poster.jpg'), target);
|
|
101
|
+
/* the path the card takes is inside the project: the project's folder is where the chat loads pictures from */
|
|
102
|
+
picked.push({ id: one.id, name: one.name, nameZh: one.nameZh, family: one.family, folder: one.folder, picture: relative(process.cwd(), target).split('\\').join('/') });
|
|
103
|
+
}
|
|
104
|
+
console.log(JSON.stringify(picked, null, 2));
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
console.error('usage: atlas.mjs --list [--family X] | --id 26 | --verify | --pick 26,32,2 [--into dir]');
|
|
109
|
+
process.exit(1);
|
package/studio/client.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import { studioHome, studioKey } from './server/projects.mjs';
|
|
|
15
15
|
const MAIN = fileURLToPath(new URL('./server/main.mjs', import.meta.url));
|
|
16
16
|
const VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
17
17
|
|
|
18
|
-
/** @typedef {{ pid?: number, supervisor?: number, origin: string, filmOrigin: string, key: string, version?: string }} Running */
|
|
18
|
+
/** @typedef {{ pid?: number, supervisor?: number, origin: string, filmOrigin: string, key: string, version?: string, ffmpeg?: boolean }} Running */
|
|
19
19
|
|
|
20
20
|
/** What a Studio says about itself, or null when nothing (or something else) answers at `origin`. */
|
|
21
21
|
async function health(/** @type {string} */ origin, ms = 1500) {
|
|
@@ -36,14 +36,14 @@ async function running() {
|
|
|
36
36
|
try { run = JSON.parse(readFileSync(join(studioHome(), 'run.json'), 'utf8')); } catch { /* none advertised */ }
|
|
37
37
|
if (run) {
|
|
38
38
|
const said = await health(run.origin);
|
|
39
|
-
if (said) return { ...run, version: said.version };
|
|
39
|
+
if (said) return { ...run, version: said.version, ffmpeg: said.ffmpeg };
|
|
40
40
|
}
|
|
41
41
|
const given = Number(process.env.AICUT_STUDIO_PORT);
|
|
42
42
|
const origin = `http://127.0.0.1:${Number.isInteger(given) && given > 0 ? given : 4747}`;
|
|
43
43
|
const said = await health(origin);
|
|
44
44
|
/* it says which home it serves as a hash of the path (the path itself is not told to anyone who asks) */
|
|
45
45
|
if (said?.home !== createHash('sha256').update(studioHome()).digest('hex') || !said.filmOrigin) return null;
|
|
46
|
-
return { origin, filmOrigin: said.filmOrigin, key: studioKey(), version: said.version };
|
|
46
|
+
return { origin, filmOrigin: said.filmOrigin, key: studioKey(), version: said.version, ffmpeg: said.ffmpeg };
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
@@ -18,9 +18,13 @@ export const GITHUB_API = 'https://api.github.com';
|
|
|
18
18
|
export const GITHUB_RAW = 'https://raw.githubusercontent.com';
|
|
19
19
|
/* files downloading at once */
|
|
20
20
|
const PARALLEL = 4;
|
|
21
|
-
/* tries at each file, and the wait before the second (doubled for each after)
|
|
22
|
-
|
|
21
|
+
/* tries at each file, and the wait before the second (doubled for each after). Three, not five: with a request limit
|
|
22
|
+
below, a host that cannot send is known in half a minute rather than in two. */
|
|
23
|
+
const TRIES = 3;
|
|
23
24
|
const RETRY_MS = 500;
|
|
25
|
+
/* One request's own limit. A host that never answers — blocked by a network, or a mirror that is down — otherwise
|
|
26
|
+
holds the fetch for the system's connect timeout, tries over, before anything is known. */
|
|
27
|
+
const REQUEST_MS = 12000;
|
|
24
28
|
/* the starts of a folder's address tried as a branch's name (a branch may have slashes in its name) */
|
|
25
29
|
const MAX_REF_PARTS = 6;
|
|
26
30
|
|
|
@@ -41,6 +45,13 @@ const pause = (ms, signal) => new Promise((done) => {
|
|
|
41
45
|
signal?.addEventListener('abort', () => { clearTimeout(timer); done(undefined); }, { once: true });
|
|
42
46
|
});
|
|
43
47
|
|
|
48
|
+
/** A request's signal: the caller's, and this module's own limit, whichever stops it first. @param {AbortSignal} [signal] */
|
|
49
|
+
export const within = (signal, ms = REQUEST_MS) => AbortSignal.any([...(signal ? [signal] : []), AbortSignal.timeout(ms)]);
|
|
50
|
+
|
|
51
|
+
/** The address of one file at a commit, on the file host `raw` (the real one when it says nothing).
|
|
52
|
+
* @param {string} raw @param {{ owner: string, repo: string }} at @param {string} commit @param {string[]} parts */
|
|
53
|
+
export const rawUrl = (raw, at, commit, parts) => `${raw || GITHUB_RAW}/${encodeURIComponent(at.owner)}/${encodeURIComponent(at.repo)}/${commit}/${encodePath(parts)}`;
|
|
54
|
+
|
|
44
55
|
/**
|
|
45
56
|
* Ask GitHub. A connection that fails is tried again, a little later each time; failing every time, it is said as a
|
|
46
57
|
* network failure. @param {string} url
|
|
@@ -49,7 +60,7 @@ const pause = (ms, signal) => new Promise((done) => {
|
|
|
49
60
|
async function request(url, { signal, accept }) {
|
|
50
61
|
for (let tries = 1; ; tries++) {
|
|
51
62
|
try {
|
|
52
|
-
return await fetch(url, { signal, headers: { accept: accept ?? 'application/vnd.github+json', 'user-agent': 'AICUT-Studio' } });
|
|
63
|
+
return await fetch(url, { signal: within(signal), headers: { accept: accept ?? 'application/vnd.github+json', 'user-agent': 'AICUT-Studio' } });
|
|
53
64
|
} catch (e) {
|
|
54
65
|
if (signal?.aborted) throw e;
|
|
55
66
|
if (tries >= TRIES) throw new FetchError('Could not reach GitHub: check your internet connection.', 502, 'network');
|