dsh-drawai 0.3.3 → 0.4.0
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/LICENSE +4142 -0
- package/README.md +43 -10
- package/lib/audio-media.js +147 -0
- package/lib/audio-service.js +66 -0
- package/lib/canvas-format.js +134 -0
- package/lib/client.js +5283 -223
- package/lib/comfyui-default-workflow.mjs +1825 -0
- package/lib/comfyui-workflow.mjs +426 -0
- package/lib/document-commands.js +12 -0
- package/lib/document-core.js +29 -0
- package/lib/drawing-tasks.js +26 -0
- package/lib/imagegen.mjs +596 -0
- package/lib/index.js +1758 -129
- package/lib/media.js +26 -13
- package/lib/mgstyle-core.js +75 -0
- package/lib/motion/apply.js +180 -0
- package/lib/motion/asset-pack-lock.js +10 -0
- package/lib/motion/asset-pack.js +335 -0
- package/lib/motion/assets.js +290 -0
- package/lib/motion/audio.js +103 -0
- package/lib/motion/audiolevel.js +63 -0
- package/lib/motion/audiomix.js +144 -0
- package/lib/motion/beats.js +337 -0
- package/lib/motion/builtin-assets.js +62 -0
- package/lib/motion/canvas-spec.js +442 -0
- package/lib/motion/capture.js +95 -0
- package/lib/motion/cards.js +80 -0
- package/lib/motion/collect.js +447 -0
- package/lib/motion/delivery.js +112 -0
- package/lib/motion/edge-speech.py +90 -0
- package/lib/motion/entry.jsx +73 -0
- package/lib/motion/export.js +200 -0
- package/lib/motion/ffmpeg.js +42 -0
- package/lib/motion/fonts.js +71 -0
- package/lib/motion/jobs.js +113 -0
- package/lib/motion/json.js +4 -0
- package/lib/motion/media-catalog.js +59 -0
- package/lib/motion/mgstyles/BRIEF-TEMPLATE.md +63 -0
- package/lib/motion/mgstyles/briefs/01-flat-vector.md +104 -0
- package/lib/motion/mgstyles/briefs/02-line-art.md +97 -0
- package/lib/motion/mgstyles/briefs/03-isometric.md +108 -0
- package/lib/motion/mgstyles/briefs/05-cel-boil.md +145 -0
- package/lib/motion/mgstyles/briefs/06-collage.md +149 -0
- package/lib/motion/mgstyles/briefs/07-liquid.md +106 -0
- package/lib/motion/mgstyles/briefs/08-morph.md +111 -0
- package/lib/motion/mgstyles/briefs/09-bauhaus.md +150 -0
- package/lib/motion/mgstyles/briefs/10-synthwave.md +151 -0
- package/lib/motion/mgstyles/briefs/12-aurora-glass.md +147 -0
- package/lib/motion/mgstyles/briefs/18-hanazi.md +140 -0
- package/lib/motion/mgstyles/briefs/19-paperclip.md +156 -0
- package/lib/motion/mgstyles/briefs/20-pixel.md +118 -0
- package/lib/motion/mgstyles/briefs/22-hud.md +118 -0
- package/lib/motion/mgstyles/catalog.d/01-flat-vector.json +34 -0
- package/lib/motion/mgstyles/catalog.d/02-line-art.json +34 -0
- package/lib/motion/mgstyles/catalog.d/03-isometric.json +35 -0
- package/lib/motion/mgstyles/catalog.d/05-cel-boil.json +28 -0
- package/lib/motion/mgstyles/catalog.d/06-collage.json +28 -0
- package/lib/motion/mgstyles/catalog.d/07-liquid.json +28 -0
- package/lib/motion/mgstyles/catalog.d/08-morph.json +28 -0
- package/lib/motion/mgstyles/catalog.d/09-bauhaus.json +28 -0
- package/lib/motion/mgstyles/catalog.d/10-synthwave.json +28 -0
- package/lib/motion/mgstyles/catalog.d/12-aurora-glass.json +28 -0
- package/lib/motion/mgstyles/catalog.d/18-hanazi.json +28 -0
- package/lib/motion/mgstyles/catalog.d/19-paperclip.json +28 -0
- package/lib/motion/mgstyles/catalog.d/20-pixel.json +28 -0
- package/lib/motion/mgstyles/catalog.d/22-hud.json +28 -0
- package/lib/motion/mgstyles/catalog.json +1356 -0
- package/lib/motion/mgstyles/upstream/README.md +147 -0
- package/lib/motion/mgstyles/upstream/README.zh-CN.md +147 -0
- package/lib/motion/mgstyles/upstream/demos/01-flat-vector/cues.json +1 -0
- package/lib/motion/mgstyles/upstream/demos/01-flat-vector/index.html +712 -0
- package/lib/motion/mgstyles/upstream/demos/02-line-art/cues.json +331 -0
- package/lib/motion/mgstyles/upstream/demos/02-line-art/film.js +676 -0
- package/lib/motion/mgstyles/upstream/demos/02-line-art/index.html +18 -0
- package/lib/motion/mgstyles/upstream/demos/02-line-art/tools/dump_timing.mjs +26 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/cues.json +109 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/index.html +25 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/anim.js +82 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/main.js +219 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/night5.js +180 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/render.js +202 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/title.js +167 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/title5.js +294 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/ui.js +141 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/world.js +1399 -0
- package/lib/motion/mgstyles/upstream/demos/05-cel-boil/cues.json +157 -0
- package/lib/motion/mgstyles/upstream/demos/05-cel-boil/index.html +34 -0
- package/lib/motion/mgstyles/upstream/demos/05-cel-boil/js/engine.js +326 -0
- package/lib/motion/mgstyles/upstream/demos/05-cel-boil/js/scene.js +2036 -0
- package/lib/motion/mgstyles/upstream/demos/06-collage/assets/gen/layout.json +157 -0
- package/lib/motion/mgstyles/upstream/demos/06-collage/cues.json +80 -0
- package/lib/motion/mgstyles/upstream/demos/06-collage/index.html +889 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/cues.json +100 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/index.html +108 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/engine.js +153 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/links.js +64 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/lookdev.js +46 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/scene.js +963 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/shaders.js +647 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/textsdf.js +114 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/type.js +50 -0
- package/lib/motion/mgstyles/upstream/demos/08-morph/cues.json +131 -0
- package/lib/motion/mgstyles/upstream/demos/08-morph/glyphs.json +1 -0
- package/lib/motion/mgstyles/upstream/demos/08-morph/index.html +901 -0
- package/lib/motion/mgstyles/upstream/demos/09-bauhaus/cues.json +270 -0
- package/lib/motion/mgstyles/upstream/demos/09-bauhaus/film.js +697 -0
- package/lib/motion/mgstyles/upstream/demos/09-bauhaus/index.html +12 -0
- package/lib/motion/mgstyles/upstream/demos/10-synthwave/cues.json +44 -0
- package/lib/motion/mgstyles/upstream/demos/10-synthwave/index.html +1028 -0
- package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/cues.json +67 -0
- package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/index.html +16 -0
- package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/main.js +967 -0
- package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/shaders.js +468 -0
- package/lib/motion/mgstyles/upstream/demos/18-hanazi/cues.json +117 -0
- package/lib/motion/mgstyles/upstream/demos/18-hanazi/index.html +541 -0
- package/lib/motion/mgstyles/upstream/demos/19-paperclip/assets/countries-110m.json +1 -0
- package/lib/motion/mgstyles/upstream/demos/19-paperclip/assets/stickers/meta.json +34 -0
- package/lib/motion/mgstyles/upstream/demos/19-paperclip/cues.json +285 -0
- package/lib/motion/mgstyles/upstream/demos/19-paperclip/index.html +599 -0
- package/lib/motion/mgstyles/upstream/demos/20-pixel/cues.json +42 -0
- package/lib/motion/mgstyles/upstream/demos/20-pixel/film.js +914 -0
- package/lib/motion/mgstyles/upstream/demos/20-pixel/index.html +18 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/cues.json +108 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/index.html +125 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/holo.js +275 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/hud.js +855 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/post.js +150 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/util.js +65 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/v5.js +142 -0
- package/lib/motion/mgstyles/upstream/harness/render.mjs +319 -0
- package/lib/motion/mgstyles/upstream/manifest.json +269 -0
- package/lib/motion/mgstyles/upstream/prompts/01-flat-vector.md +98 -0
- package/lib/motion/mgstyles/upstream/prompts/02-line-art.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/03-isometric.md +97 -0
- package/lib/motion/mgstyles/upstream/prompts/05-cel-boil.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/06-collage.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/07-liquid.md +98 -0
- package/lib/motion/mgstyles/upstream/prompts/08-morph.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/09-bauhaus.md +96 -0
- package/lib/motion/mgstyles/upstream/prompts/10-synthwave.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/12-aurora-glass.md +96 -0
- package/lib/motion/mgstyles/upstream/prompts/18-hanazi.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/19-paperclip.md +96 -0
- package/lib/motion/mgstyles/upstream/prompts/20-pixel.md +96 -0
- package/lib/motion/mgstyles/upstream/prompts/22-hud.md +95 -0
- package/lib/motion/mgstyles/upstream/rubric.md +51 -0
- package/lib/motion/mgstyles/upstream/template.md +36 -0
- package/lib/motion/pixelqa.js +198 -0
- package/lib/motion/preview.js +95 -0
- package/lib/motion/project.js +395 -0
- package/lib/motion/qa.js +290 -0
- package/lib/motion/reference-media.jsx +10 -0
- package/lib/motion/render-settings.js +112 -0
- package/lib/motion/render.js +159 -0
- package/lib/motion/scene-kit.js +183 -0
- package/lib/motion/sfx.js +232 -0
- package/lib/motion/shotcraft/ClipCard.tsx +204 -0
- package/lib/motion/shotcraft/catalog.json +2461 -0
- package/lib/motion/shotcraft/upstream/SKILL.md +286 -0
- package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -0
- package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -0
- package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -0
- package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -0
- package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -0
- package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -0
- package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -0
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -0
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -0
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -0
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/__pycache__/sfx-source.cpython-313.pyc +0 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -0
- package/lib/motion/shotcraft/upstream/demos/README.md +120 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -0
- package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +389 -0
- package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -0
- package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -0
- package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -0
- package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -0
- package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -0
- package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -0
- package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -0
- package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -0
- package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -0
- package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -0
- package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -0
- package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -0
- package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -0
- package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -0
- package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -0
- package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -0
- package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -0
- package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -0
- package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -0
- package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -0
- package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -0
- package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -0
- package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -0
- package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -0
- package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -0
- package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -0
- package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -0
- package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -0
- package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -0
- package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -0
- package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -0
- package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -0
- package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -0
- package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -0
- package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -0
- package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -0
- package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -0
- package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -0
- package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -0
- package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -0
- package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -0
- package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -0
- package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -0
- package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -0
- package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -0
- package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -0
- package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -0
- package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -0
- package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -0
- package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -0
- package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -0
- package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -0
- package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -0
- package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -0
- package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -0
- package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -0
- package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -0
- package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -0
- package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -0
- package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -0
- package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -0
- package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -0
- package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -0
- package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -0
- package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -0
- package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -0
- package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -0
- package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -0
- package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -0
- package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -0
- package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -0
- package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -0
- package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -0
- package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -0
- package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -0
- package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -0
- package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -0
- package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -0
- package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -0
- package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -0
- package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -0
- package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -0
- package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -0
- package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -0
- package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -0
- package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -0
- package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -0
- package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -0
- package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -0
- package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -0
- package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -0
- package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -0
- package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -0
- package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -0
- package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -0
- package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -0
- package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -0
- package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -0
- package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -0
- package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -0
- package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -0
- package/lib/motion/shotcraft/upstream/manifest.json +2715 -0
- package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -0
- package/lib/motion/shotcraft/upstream/references/final-review.md +121 -0
- package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -0
- package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -0
- package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -0
- package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -0
- package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -0
- package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -0
- package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -0
- package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -0
- package/lib/motion/shotcraft/upstream/references/workbench.md +157 -0
- package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -0
- package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -0
- package/lib/motion/shotcraft/upstream/template/package.json +20 -0
- package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -0
- package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +389 -0
- package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -0
- package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -0
- package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -0
- package/lib/motion/spec.js +113 -0
- package/lib/motion/style-engine.js +153 -0
- package/lib/motion/style-frames.js +268 -0
- package/lib/motion/sync.js +214 -0
- package/lib/motion/theme.js +121 -0
- package/lib/motion/voice.js +417 -0
- package/lib/motion-agent-files.js +82 -0
- package/lib/motion-agent-protocol.js +66 -0
- package/lib/motion-agent-tools.js +196 -0
- package/lib/motion-agent.js +171 -0
- package/lib/motion-capture.js +92 -0
- package/lib/motion-core.js +238 -0
- package/lib/motion-film-review.js +71 -0
- package/lib/motion-library.js +210 -0
- package/lib/motion-planner.js +254 -0
- package/lib/motion-project.js +80 -0
- package/lib/motion-render-worker.js +145 -0
- package/lib/motion-session.js +32 -0
- package/lib/motion-source.js +49 -0
- package/lib/motion-tasks.js +452 -0
- package/lib/motion-vision.js +43 -0
- package/lib/mxfile.js +27 -7
- package/lib/routing/node-runtime.js +14 -0
- package/lib/routing/router.js +211 -0
- package/lib/routing/vendor/README.md +96 -0
- package/lib/routing/vendor/libavoid-routing.js +753 -0
- package/lib/routing/vendor/libavoid.min.js +59 -0
- package/lib/shotcard-core.js +39 -0
- package/lib/shotcard-reference.js +56 -0
- package/lib/style-kernel.js +37 -3
- package/lib/task-patches.js +26 -2
- package/lib/video-export.js +17 -2
- package/package.json +29 -4
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
// 09-bauhaus — KONSTRUKTION · 20 SCHLÄGE (refinement round 1)
|
|
2
|
+
// Canvas2D ink-separation plates (knockout) -> WebGL press pass (paper, misregistration, tooth, cascade).
|
|
3
|
+
// Cascade (6-8 s) is done in the shader as a two-sided card system: FRONT = poster + poster-derived field,
|
|
4
|
+
// BACK = giant ▲■● triad on a black ground. R1 turns 120 tiles, R2 flips 240 cards to the back, R3 slides
|
|
5
|
+
// columns, R4 flips the cards home converging on the frame centre. Every frame is a pure function of t.
|
|
6
|
+
const W = 1920, H = 1080, M = 120, Y0 = 60, CX = 960, CY = 540;
|
|
7
|
+
window.DEMO = { width: W, height: H, fps: 30, duration: 10, motionBlur: { samples: 8, shutter: 0.5 } };
|
|
8
|
+
const Q = new URLSearchParams(location.search);
|
|
9
|
+
const MB = +(Q.get('mb') || window.DEMO.motionBlur.samples); // harness samples per frame (slice for in-shader taps)
|
|
10
|
+
// reel v5 (?v5=1): title bar 几何构成 · 包豪斯 on the poster + window.linkAt(t); ?nolink=dot,disc2,rule,pivot hides link
|
|
11
|
+
// elements. Without v5 every code path below is the v4 film, unchanged.
|
|
12
|
+
const V5 = Q.get('v5') === '1';
|
|
13
|
+
const NOLINK = new Set(V5 ? (Q.get('nolink') || '').split(',').map(s => s.trim()).filter(Boolean) : []);
|
|
14
|
+
const BASE = '/demos/09-bauhaus/';
|
|
15
|
+
const cues = await (await fetch(BASE + 'cues.json')).json();
|
|
16
|
+
const EV = Object.fromEntries(cues.events.map(e => [e.id, e]));
|
|
17
|
+
const RP = Object.fromEntries(cues.ripples.map(r => [r.id, r]));
|
|
18
|
+
const DROP = cues.drop, FREEZE = cues.freeze;
|
|
19
|
+
|
|
20
|
+
// ---------------------------------------------------------------- easing / helpers
|
|
21
|
+
const clamp = (x, a = 0, b = 1) => Math.min(b, Math.max(a, x));
|
|
22
|
+
const io2 = u => (u < 0.5 ? 2 * u * u : 1 - Math.pow(-2 * u + 2, 2) / 2); // power2.inOut
|
|
23
|
+
const snap = t => Math.round(t * 30) / 30; // frame-snapped time: gates for hard cuts, so mb sub-samples never straddle a cut
|
|
24
|
+
const in2 = u => u * u; // power2.in (drops land dead)
|
|
25
|
+
const prog = (t, t0, t1) => clamp((t - t0) / (t1 - t0));
|
|
26
|
+
const lerp = (a, b, u) => a + (b - a) * u;
|
|
27
|
+
const DEG = Math.PI / 180;
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------- plates
|
|
30
|
+
function mk() { const c = document.createElement('canvas'); c.width = W; c.height = H; return c; }
|
|
31
|
+
const cA = mk(), cB = mk(), cC = mk(), cD = mk();
|
|
32
|
+
const a = cA.getContext('2d', { alpha: false });
|
|
33
|
+
const b = cB.getContext('2d', { alpha: false });
|
|
34
|
+
// plate A: R = yellow, G = red, B = blue. plate B: R = black. (opaque colours => exact knockout)
|
|
35
|
+
const INK = { Y: ['#ff0000', '#000000'], R: ['#00ff00', '#000000'], B: ['#0000ff', '#000000'], K: ['#000000', '#ff0000'], P: ['#000000', '#000000'] };
|
|
36
|
+
let CT = [a, b]; // current plate pair (front sheet a/b, back sheet c/d at init)
|
|
37
|
+
function paint(ink, path, rule = 'nonzero') {
|
|
38
|
+
const [ca, cb] = INK[ink];
|
|
39
|
+
if (ink !== 'K') { CT[0].fillStyle = ca; CT[0].beginPath(); path(CT[0]); CT[0].fill(rule); } // black overprints (trap)
|
|
40
|
+
CT[1].fillStyle = cb; CT[1].beginPath(); path(CT[1]); CT[1].fill(rule);
|
|
41
|
+
}
|
|
42
|
+
const both = (fn) => { fn(CT[0]); fn(CT[1]); };
|
|
43
|
+
const P = {
|
|
44
|
+
circle: (cx, cy, r) => c => c.arc(cx, cy, r, 0, Math.PI * 2),
|
|
45
|
+
ring: (cx, cy, r0, r1) => c => { c.arc(cx, cy, r1, 0, Math.PI * 2); c.moveTo(cx + r0, cy); c.arc(cx, cy, r0, 0, Math.PI * 2, true); },
|
|
46
|
+
rect: (x, y, w, h) => c => c.rect(x, y, w, h),
|
|
47
|
+
poly: (pts) => c => { c.moveTo(pts[0][0], pts[0][1]); for (let i = 1; i < pts.length; i++) c.lineTo(pts[i][0], pts[i][1]); c.closePath(); },
|
|
48
|
+
sector: (px, py, r, a0) => c => { c.moveTo(px, py); c.arc(px, py, r, a0, a0 + Math.PI / 2); c.closePath(); },
|
|
49
|
+
semi: (cx, cy, r, a0) => c => { c.moveTo(cx + r * Math.cos(a0), cy + r * Math.sin(a0)); c.arc(cx, cy, r, a0, a0 + Math.PI); c.closePath(); },
|
|
50
|
+
};
|
|
51
|
+
function text(ink, str, x, y, font, track = 0, align = 'left', base = 'alphabetic') {
|
|
52
|
+
for (const [c, col] of (ink === 'K' ? [[CT[1], INK.K[1]]] : [[CT[0], INK[ink][0]], [CT[1], INK[ink][1]]])) {
|
|
53
|
+
c.font = font; c.letterSpacing = track + 'px'; c.textAlign = align; c.textBaseline = base; c.fillStyle = col;
|
|
54
|
+
c.fillText(str, x, y); c.letterSpacing = '0px'; c.textAlign = 'left';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------- type metrics
|
|
59
|
+
let TYPE = null;
|
|
60
|
+
function measureType() {
|
|
61
|
+
const f = (s) => `900 ${s}px "Poppins"`;
|
|
62
|
+
a.font = f(100);
|
|
63
|
+
const capH = a.measureText('H').actualBoundingBoxAscent / 100;
|
|
64
|
+
const size = M / capH; // cap height = exactly one module
|
|
65
|
+
a.font = f(size);
|
|
66
|
+
const word = 'BAUHAUS'.split('');
|
|
67
|
+
const m = word.map(ch => a.measureText(ch));
|
|
68
|
+
const adv = m.map(x => x.width);
|
|
69
|
+
const bbL0 = m[0].actualBoundingBoxLeft, bbRn = m[word.length - 1].actualBoundingBoxRight;
|
|
70
|
+
let sumAdv = 0; for (let i = 0; i < word.length - 1; i++) sumAdv += adv[i];
|
|
71
|
+
const len = 8 * M; // ink extent = exactly eight modules
|
|
72
|
+
const track = (len - (bbL0 + sumAdv + bbRn)) / (word.length - 1);
|
|
73
|
+
const xs = []; let x = bbL0; for (let i = 0; i < word.length; i++) { xs.push(x); x += adv[i] + track; }
|
|
74
|
+
// caption: German words along the rotated baseline; each Chinese pair is centred on its German word
|
|
75
|
+
a.font = '600 24px "Poppins"'; a.letterSpacing = '7.2px';
|
|
76
|
+
const cap = ['FORM', ' · ', 'FARBE', ' · ', 'FUNKTION'];
|
|
77
|
+
let o = 0; const mids = [];
|
|
78
|
+
for (const w of cap) { const wd = a.measureText(w).width; if (w.trim().length > 1) mids.push(o + (wd - 7.2) / 2); o += wd; }
|
|
79
|
+
a.letterSpacing = '0px';
|
|
80
|
+
a.font = '600 13px "Poppins"'; a.letterSpacing = '2.6px';
|
|
81
|
+
const dw = a.measureText('0').width, lw = a.measureText('SCHLAG ').width;
|
|
82
|
+
a.letterSpacing = '0px';
|
|
83
|
+
TYPE = { size, word, xs, track, mids, dw, lw };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ---------------------------------------------------------------- composition (final coords)
|
|
87
|
+
const GT0 = EV.group_turn.t0, GT1 = EV.group_turn.t;
|
|
88
|
+
// 12-detent escapement: the eased progress is quantised into 7.5° teeth (move in the last 65 % of each tooth, then hold);
|
|
89
|
+
// the teeth land exactly on the audio ratchet ticks (io2_inv(k/12)); fast in the middle, visibly stepped at both ends.
|
|
90
|
+
function groupAngle(t) {
|
|
91
|
+
const P_ = io2(prog(t, GT0, GT1)), x = P_ * 12, k = Math.min(12, Math.floor(x + 1e-9)), f = x - k;
|
|
92
|
+
return (-90 + 7.5 * (k + io2(clamp((f - 0.35) / 0.65)))) * DEG;
|
|
93
|
+
}
|
|
94
|
+
const cascOn = t => { const q = snap(t); return q >= DROP && q < FREEZE; };
|
|
95
|
+
|
|
96
|
+
function target(x, y) { // construction target (Passkreuz) that pre-announces a landing on the off-beat
|
|
97
|
+
paint('K', P.ring(x, y, 21, 25));
|
|
98
|
+
paint('K', P.rect(x - 44, y - 2, 32, 4)); paint('K', P.rect(x + 12, y - 2, 32, 4));
|
|
99
|
+
paint('K', P.rect(x - 2, y - 44, 4, 32)); paint('K', P.rect(x - 2, y + 12, 4, 32));
|
|
100
|
+
paint('K', P.circle(x, y, 4));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function drawGroup(t, opt = {}) { // everything inside the central 8x8 square, drawn in final coordinates
|
|
104
|
+
both(c => { c.save(); c.translate(CX, CY); c.rotate(groupAngle(t)); c.translate(-CX, -CY); });
|
|
105
|
+
// off-beat construction targets (1.25 / 1.75 / 2.25 / 2.75): drawn first, the landing ink knocks them out
|
|
106
|
+
for (let i = 1; i <= 4; i++) { const e = EV['target' + i]; if (snap(t) >= e.t && snap(t) < e.until) target(e.gx, e.gy); }
|
|
107
|
+
const e1 = EV.circle_land;
|
|
108
|
+
if (t >= e1.t0 && (opt.keepDot || !NOLINK.has('dot'))) { // v5 ?nolink=dot: the red disc is not printed
|
|
109
|
+
const u = in2(prog(t, e1.t0, e1.t));
|
|
110
|
+
const dx = (1 - u) * 6 * M;
|
|
111
|
+
const sl = io2(prog(t, EV.circle_slide.t0, EV.circle_slide.t)); // slides one module into contact
|
|
112
|
+
paint('R', P.circle(840 + dx, 300 - M * (1 - sl), 240));
|
|
113
|
+
}
|
|
114
|
+
const e4 = EV.sq_scale;
|
|
115
|
+
if (t >= e4.t0) {
|
|
116
|
+
const s = io2(prog(t, e4.t0, e4.t));
|
|
117
|
+
if (s > 0.001) paint('B', P.rect(1080, 300 - 240 * s, 240 * s + 4 * s, 240 * s)); // +4 px trap under the bar
|
|
118
|
+
}
|
|
119
|
+
const e3 = EV.tri_in, e3f = EV.tri_flip;
|
|
120
|
+
if (t >= e3.t0) {
|
|
121
|
+
const sy = t < e3.t ? -io2(prog(t, e3.t0, e3.t)) : lerp(-1, 1, io2(prog(t, e3f.t0, e3f.t)));
|
|
122
|
+
const apexY = 1020 - 480 * sy;
|
|
123
|
+
if (Math.abs(sy) > 0.002) paint('Y', P.poly([[600, 1020], [1080, 1020], [840, apexY]]));
|
|
124
|
+
}
|
|
125
|
+
const e2 = EV.bar_land;
|
|
126
|
+
if (t >= e2.t0) {
|
|
127
|
+
const u = in2(prog(t, e2.t0, e2.t));
|
|
128
|
+
paint('K', P.rect(1320, 60, 120, 960 * u));
|
|
129
|
+
}
|
|
130
|
+
// pivot: dot + ring stamp the frame centre at 3.00 (ring leaves after the turn); dot is off during the cascade
|
|
131
|
+
if (snap(t) >= EV.pivot.t && !opt.noRule && !cascOn(t)) {
|
|
132
|
+
if (!NOLINK.has('pivot')) paint('K', P.circle(CX, CY, 20));
|
|
133
|
+
const rr = io2(prog(t, EV.pivot.t, GT0));
|
|
134
|
+
if (t < GT1 + 0.25 && rr > 0.001) paint('K', c => { const a0 = -Math.PI / 2, a1 = a0 + Math.PI * 2 * rr;
|
|
135
|
+
c.arc(CX, CY, 60, a0, a1); c.arc(CX, CY, 56, a1, a0, true); c.closePath(); });
|
|
136
|
+
}
|
|
137
|
+
both(c => c.restore());
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function drawOuter(t, opt = {}) {
|
|
141
|
+
const e5 = EV.semi_slide;
|
|
142
|
+
if (t >= e5.t0) {
|
|
143
|
+
const u = io2(prog(t, e5.t0, e5.t));
|
|
144
|
+
both(c => { c.save(); c.beginPath(); c.rect(1436, 0, W - 1436, H); c.clip(); }); // 4 px trap under the bar
|
|
145
|
+
paint('B', P.semi(1436 - 240 * (1 - u), 780, 244, -90 * DEG));
|
|
146
|
+
both(c => c.restore());
|
|
147
|
+
}
|
|
148
|
+
const e6 = EV.qd_sweep;
|
|
149
|
+
if (t >= e6.t0) {
|
|
150
|
+
const u = io2(prog(t, e6.t0, e6.t));
|
|
151
|
+
both(c => { c.save(); c.beginPath(); c.rect(120, 60, 1680, 960); c.clip(); }); // r2: swing stays inside the trim
|
|
152
|
+
paint('K', P.sector(600, 1020, 240, (90 + 90 * u) * DEG));
|
|
153
|
+
both(c => c.restore());
|
|
154
|
+
}
|
|
155
|
+
// horizon rule y=540, x 360 -> trim (1800); off during the cascade (it would be torn by the remap), back on the freeze
|
|
156
|
+
const er = EV.rule;
|
|
157
|
+
if (t >= er.t0 && !opt.noRule && !cascOn(t) && !NOLINK.has('rule')) {
|
|
158
|
+
const u = io2(prog(t, er.t0, er.t));
|
|
159
|
+
paint('K', P.rect(360, 537, (1800 - 360) * u, 6));
|
|
160
|
+
}
|
|
161
|
+
// RED 2x2 square cuts in on the bar/horizon corner at 5.50; at 5.75 its outer corner is swept round by the compass:
|
|
162
|
+
// it becomes a quarter-disc pivoting at (1440,540), stacked on the blue semicircle, touching bar and rule
|
|
163
|
+
const e7 = EV.red_in, e7s = EV.red_split;
|
|
164
|
+
if (snap(t) >= e7.t) {
|
|
165
|
+
const r = 240 * io2(prog(t, e7s.t0, e7s.t));
|
|
166
|
+
paint('R', c => { c.moveTo(1436, 540); c.lineTo(1436, 300); c.lineTo(1440, 300);
|
|
167
|
+
if (r < 0.5) c.lineTo(1680, 300); else c.arcTo(1680, 300, 1680, 540, r);
|
|
168
|
+
c.lineTo(1680, 540); c.closePath(); });
|
|
169
|
+
}
|
|
170
|
+
// black overprints: re-print the bar over the colour traps (semicircle / red quarter-disc tuck 4 px under it)
|
|
171
|
+
if (t >= GT1) paint('K', P.rect(1320, 60, 120, 960));
|
|
172
|
+
// ticker — black quarter-disc R120 pivoting at (480,180); the 4th tick lands on the last frame (360° = resolved)
|
|
173
|
+
if (snap(t) >= EV.ticker_in.t) {
|
|
174
|
+
let q = 0;
|
|
175
|
+
for (const tt of cues.ticker.concat(cues.tickerVisualOnly || [])) q += io2(prog(t, tt - 0.25, tt));
|
|
176
|
+
paint('K', P.sector(480, 180, 120, (180 + 90 * q) * DEG));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ---------------------------------------------------------------- front field: every empty cell inside the trim takes
|
|
181
|
+
// the ink and form of its nearest poster shape (red petals round the circle, yellow half-squares by the triangle,
|
|
182
|
+
// blue squares / half-discs by the square and semicircle, black stripes by the bar, black quarter-discs by the black discs)
|
|
183
|
+
const sdBox = (x, y, x0, y0, x1, y1) => { const dx = Math.max(x0 - x, 0, x - x1), dy = Math.max(y0 - y, 0, y - y1); return Math.hypot(dx, dy); };
|
|
184
|
+
function sdSeg(px, py, ax, ay, bx, by) { const vx = bx - ax, vy = by - ay; const h = clamp(((px - ax) * vx + (py - ay) * vy) / (vx * vx + vy * vy));
|
|
185
|
+
return Math.hypot(px - ax - vx * h, py - ay - vy * h); }
|
|
186
|
+
const SH = [
|
|
187
|
+
{ ink: 'R', form: 'qd', cx: 840, cy: 300, w: 1.6, d: (x, y) => Math.max(0, Math.hypot(x - 840, y - 300) - 240) },
|
|
188
|
+
{ ink: 'R', form: 'qd', cx: 1440, cy: 540, d: (x, y) => sdBox(x, y, 1440, 300, 1680, 540) },
|
|
189
|
+
{ ink: 'B', form: 'sq', cx: 1200, cy: 180, d: (x, y) => sdBox(x, y, 1080, 60, 1320, 300) },
|
|
190
|
+
{ ink: 'B', form: 'semi', cx: 1440, cy: 780, d: (x, y) => x < 1440 ? sdBox(x, y, 1440, 540, 1440, 1020) : Math.max(0, Math.hypot(x - 1440, y - 780) - 240) },
|
|
191
|
+
{ ink: 'Y', form: 'hst', cx: 840, cy: 860, d: (x, y) => Math.min(sdSeg(x, y, 600, 1020, 840, 540), sdSeg(x, y, 1080, 1020, 840, 540), sdSeg(x, y, 600, 1020, 1080, 1020)) },
|
|
192
|
+
{ ink: 'K', form: 'bar', cx: 1380, cy: 540, d: (x, y) => sdBox(x, y, 1320, 60, 1440, 1020) },
|
|
193
|
+
{ ink: 'K', form: 'qd', cx: 600, cy: 1020, d: (x, y) => sdBox(x, y, 360, 780, 600, 1020) },
|
|
194
|
+
];
|
|
195
|
+
let FIELD = [];
|
|
196
|
+
function buildField() {
|
|
197
|
+
renderPlates(DROP - 0.001, { noField: true, noRule: true, keepDot: true }); // field never depends on ?nolink
|
|
198
|
+
const da = a.getImageData(0, 0, W, H).data, db = b.getImageData(0, 0, W, H).data;
|
|
199
|
+
const [tx0, ty0, tx1, ty1] = cues.trim;
|
|
200
|
+
for (let r = 0; r < 8; r++) for (let c = tx0 / M; c < tx1 / M; c++) {
|
|
201
|
+
let ink = 0;
|
|
202
|
+
for (let y = Y0 + r * M + 3; y < Y0 + (r + 1) * M - 2; y += 5) for (let x = c * M + 3; x < (c + 1) * M - 2; x += 5) {
|
|
203
|
+
const i = (y * W + x) * 4; ink = Math.max(ink, da[i], da[i + 1], da[i + 2], db[i]);
|
|
204
|
+
}
|
|
205
|
+
if (ink > 8) continue;
|
|
206
|
+
const x0 = c * M, y0 = Y0 + r * M, mx = x0 + M / 2, my = y0 + M / 2;
|
|
207
|
+
let best = SH[0], bd = 1e9;
|
|
208
|
+
for (const s of SH) { const d = s.d(mx, my) / (s.w || 1); if (d < bd - 1e-6) { bd = d; best = s; } }
|
|
209
|
+
const kx = best.cx < mx ? x0 : x0 + M, ky = best.cy < my ? y0 : y0 + M; // cell corner facing the shape
|
|
210
|
+
const form = best.ink === 'K' && best.form === 'qd' && (r + c) % 2 === 1 ? 'bar' : best.form; // r2: lighten the black block
|
|
211
|
+
FIELD.push({ x0, y0, kx, ky, mx, my, ink: best.ink, form, sx: best.cx, sy: best.cy });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function drawFieldCell(f) {
|
|
215
|
+
const { x0, y0, kx, ky, mx, my } = f;
|
|
216
|
+
if (f.form === 'qd') {
|
|
217
|
+
const a0 = kx === x0 ? (ky === y0 ? 0 : 270) : (ky === y0 ? 90 : 180);
|
|
218
|
+
paint(f.ink, P.sector(kx, ky, M, a0 * DEG));
|
|
219
|
+
} else if (f.form === 'hst') {
|
|
220
|
+
paint(f.ink, P.poly([[kx, ky], [kx === x0 ? x0 + M : x0, ky], [kx, ky === y0 ? y0 + M : y0]]));
|
|
221
|
+
} else if (f.form === 'sq') {
|
|
222
|
+
paint(f.ink, P.rect(kx === x0 ? x0 : x0 + M / 2, ky === y0 ? y0 : y0 + M / 2, M / 2, M / 2));
|
|
223
|
+
} else if (f.form === 'semi') {
|
|
224
|
+
const hz = Math.abs(f.sx - mx) >= Math.abs(f.sy - my);
|
|
225
|
+
if (hz) paint(f.ink, P.semi(kx, my, M / 2, (kx === x0 ? -90 : 90) * DEG));
|
|
226
|
+
else paint(f.ink, P.semi(mx, ky, M / 2, (ky === y0 ? 0 : 180) * DEG));
|
|
227
|
+
} else if (f.form === 'bar') {
|
|
228
|
+
paint(f.ink, P.rect(kx === x0 ? x0 : x0 + M / 2, y0, M / 2, M));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function drawField(t) { if (cascOn(t)) for (const f of FIELD) drawFieldCell(f); }
|
|
232
|
+
|
|
233
|
+
// ---------------------------------------------------------------- back sheet: the giant Kandinsky triad (static)
|
|
234
|
+
function drawBack(nLab = 3) {
|
|
235
|
+
CT = [cC.getContext('2d', { alpha: false }), cD.getContext('2d', { alpha: false })];
|
|
236
|
+
for (const c of CT) { c.fillStyle = '#000'; c.fillRect(0, 0, W, H); }
|
|
237
|
+
const [x0, y0, x1, y1] = cues.trim;
|
|
238
|
+
paint('K', P.rect(x0, y0, x1 - x0, y1 - y0));
|
|
239
|
+
const tri = [[120, 780], [600, 780], [360, 300]];
|
|
240
|
+
paint('Y', P.poly(tri)); // ▲ 4x4 modules
|
|
241
|
+
paint('R', P.rect(720, 300, 480, 480)); // ■ 4x4
|
|
242
|
+
const disc2 = !NOLINK.has('disc2'); // v5 ?nolink=disc2: the back-sheet blue disc is not printed
|
|
243
|
+
if (disc2) paint('B', P.circle(1560, 540, 240)); // ● Ø 4 modules
|
|
244
|
+
const cc = CT[0]; cc.lineJoin = 'miter'; cc.lineWidth = 5; // trap: colour spreads 2.5 px over the knocked-out black
|
|
245
|
+
cc.strokeStyle = INK.Y[0]; cc.beginPath(); P.poly(tri)(cc); cc.stroke();
|
|
246
|
+
cc.strokeStyle = INK.R[0]; cc.beginPath(); cc.rect(720, 300, 480, 480); cc.stroke();
|
|
247
|
+
if (disc2) { cc.strokeStyle = INK.B[0]; cc.beginPath(); P.circle(1560, 540, 240)(cc); cc.stroke(); }
|
|
248
|
+
const lab = [['GELB', '黄', 360], ['ROT', '红', 960], ['BLAU', '蓝', 1560]];
|
|
249
|
+
for (const [de, zh, x] of lab.slice(0, nLab)) { // knocked-out labels (paper shows through), stamped on 7.0
|
|
250
|
+
text('P', de, x - 8, 900, '600 24px "Poppins"', 7.2, 'right');
|
|
251
|
+
text('P', zh, x + 16, 901, '700 26px "Noto Sans SC"', 0, 'left');
|
|
252
|
+
}
|
|
253
|
+
CT = [a, b];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function drawType(t) {
|
|
257
|
+
if (!TYPE) return;
|
|
258
|
+
const L = cues.letters;
|
|
259
|
+
const tg = snap(t);
|
|
260
|
+
const n = Math.min(L.n, Math.floor((tg - L.t0) / L.step + 1e-6) + 1);
|
|
261
|
+
if (tg >= L.t0 && n > 0) {
|
|
262
|
+
for (const [c, col] of [[a, INK.K[0]], [b, INK.K[1]]]) {
|
|
263
|
+
c.save(); c.translate(240, 1020); c.rotate(-Math.PI / 2);
|
|
264
|
+
c.font = `900 ${TYPE.size}px "Poppins"`; c.fillStyle = col; c.textBaseline = 'alphabetic';
|
|
265
|
+
for (let i = 0; i < n; i++) c.fillText(TYPE.word[i], TYPE.xs[i], 0);
|
|
266
|
+
c.restore();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (tg >= EV.type_small.t) {
|
|
270
|
+
// German caption rotated with the headline (reads bottom -> top, baseline x = 291)
|
|
271
|
+
for (const [c, k] of [[a, 0], [b, 1]]) {
|
|
272
|
+
c.save(); c.fillStyle = INK.K[k]; c.translate(0, 1020); c.rotate(-Math.PI / 2);
|
|
273
|
+
c.font = `600 24px "Poppins"`; c.letterSpacing = '7.2px'; c.textBaseline = 'alphabetic';
|
|
274
|
+
c.fillText('FORM · FARBE · FUNKTION', 0, 291);
|
|
275
|
+
c.letterSpacing = '0px'; c.restore();
|
|
276
|
+
}
|
|
277
|
+
// Chinese upright (竖排), each pair anchored beside its German word: 形式 | FORM, 色彩 | FARBE, 功能 | FUNKTION
|
|
278
|
+
const zh = [['形', '式'], ['色', '彩'], ['功', '能']];
|
|
279
|
+
zh.forEach((pr, i) => { const yc = 1020 - TYPE.mids[i];
|
|
280
|
+
text('K', pr[0], 324, yc - 3, '700 26px "Noto Sans SC"', 0, 'center', 'alphabetic');
|
|
281
|
+
text('K', pr[1], 324, yc + 27, '700 26px "Noto Sans SC"', 0, 'center', 'alphabetic'); });
|
|
282
|
+
// Kandinsky key ▲ ■ ● (1923): yellow triangle, red square, blue circle — top of column 2
|
|
283
|
+
paint('Y', P.poly([[264, 84 + 24], [288, 84 + 24], [276, 84]]));
|
|
284
|
+
paint('R', P.rect(264, 120, 24, 24));
|
|
285
|
+
paint('B', P.circle(276, 168, 12));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ---------------------------------------------------------------- reel v5 title: 几何构成 · 包豪斯
|
|
290
|
+
// A black title bar ruled over the two bottom rows (x 360-1800, y 780-1020 = 12 x 2 modules), joined to the vertical bar,
|
|
291
|
+
// carrying 几何构成 knocked out to paper and 包豪斯 in yellow ink (Alimama ShuHeiTi, 180 px em = 1.5 modules per glyph,
|
|
292
|
+
// cells 420-1140 / 1200-1740). With the vertical Poppins BAUHAUS it locks up as an L. It is printed on the FRONT sheet
|
|
293
|
+
// from the front reset (7.1, while every card shows its back), so the R4 cards turning home reveal it (7.5-7.92); it
|
|
294
|
+
// freezes with the poster at 8.0, drifts with the plates 8.5-9.47 and is struck into register by the 9.5 press lock.
|
|
295
|
+
const TB = { x0: 360, y0: 780, x1: 1800, y1: 1020, em: 180, font: '700 180px "Alimama ShuHeiTi"',
|
|
296
|
+
cells: [['几', 420], ['何', 600], ['构', 780], ['成', 960], ['包', 1200], ['豪', 1380], ['斯', 1560]] };
|
|
297
|
+
let TBY = 0; // common baseline: ink of the 7 glyphs centred on y 900
|
|
298
|
+
function measureTitleV5() {
|
|
299
|
+
a.font = TB.font; let A = 0, D = 0;
|
|
300
|
+
for (const [g] of TB.cells) { const m = a.measureText(g); A = Math.max(A, m.actualBoundingBoxAscent); D = Math.max(D, m.actualBoundingBoxDescent); }
|
|
301
|
+
TBY = (TB.y0 + TB.y1) / 2 + (A - D) / 2;
|
|
302
|
+
}
|
|
303
|
+
const titleOn = t => V5 && snap(t) >= cues.frontReset;
|
|
304
|
+
function drawTitleV5(t) {
|
|
305
|
+
if (!titleOn(t)) return;
|
|
306
|
+
CT = [a, b];
|
|
307
|
+
a.fillStyle = '#000'; a.fillRect(TB.x0, TB.y0 + 4, TB.x1 - TB.x0, TB.y1 - TB.y0 + 4); // colours under the bar knocked out (4 px trap;
|
|
308
|
+
// +4 px below the trim so the semicircle's r 244 overhang does not peek out under the bar)
|
|
309
|
+
paint('K', P.rect(TB.x0, TB.y0, TB.x1 - TB.x0, TB.y1 - TB.y0));
|
|
310
|
+
TB.cells.forEach(([g, x], i) => text(i < 4 ? 'P' : 'Y', g, x + TB.em / 2, TBY, TB.font, 0, 'center'));
|
|
311
|
+
a.font = TB.font; a.textAlign = 'center'; a.lineJoin = 'miter'; a.lineWidth = 5; a.strokeStyle = INK.Y[0]; // yellow spreads 2.5 px (trap)
|
|
312
|
+
for (const [g, x] of TB.cells.slice(4)) a.strokeText(g, x + TB.em / 2, TBY);
|
|
313
|
+
a.textAlign = 'left';
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function drawMarks(t) {
|
|
317
|
+
for (const y of [30, 1050]) { paint('K', P.ring(CX, y, 10, 11.5)); paint('K', P.rect(CX - 18, y - 0.75, 36, 1.5)); paint('K', P.rect(CX - 0.75, y - 18, 1.5, 36)); }
|
|
318
|
+
if (snap(t) >= EV.marks.t) for (const [x, y, sx] of [[120, 60, -1], [1800, 60, 1], [120, 1020, -1], [1800, 1020, 1]]) {
|
|
319
|
+
const sy = y < 540 ? -1 : 1;
|
|
320
|
+
paint('K', P.rect(sx < 0 ? x - 40 : x + 12, y - 0.75, 28, 1.5));
|
|
321
|
+
paint('K', P.rect(x - 0.75, sy < 0 ? y - 40 : y + 12, 1.5, 28));
|
|
322
|
+
}
|
|
323
|
+
const firsts = [['Y', EV.tri_in.t], ['R', EV.circle_land.t0 + 0.05], ['B', EV.sq_scale.t0 + 0.05], ['K', EV.bar_land.t0 + 0.05]];
|
|
324
|
+
firsts.forEach(([ink, tt], i) => { if (snap(t) >= tt) paint(ink, P.rect(1500 + i * 30, 1043, 24, 14)); });
|
|
325
|
+
const F = '600 13px "Poppins"';
|
|
326
|
+
text('K', 'BOGEN 09 — KONSTRUKTION IN 20 SCHLÄGEN · 120 BPM · M = 120 PX', 152, 1050, F, 2.6, 'left', 'middle');
|
|
327
|
+
text('K', 'KINETISCHES PLAKAT · Nº 09 · WEIMAR 1919', 1768, 30, F, 2.6, 'right', 'middle');
|
|
328
|
+
// beat counter (steps on every beat; 20/20 lands with the press lock at 9.5)
|
|
329
|
+
if (TYPE) {
|
|
330
|
+
const n = clamp(Math.floor(snap(t) / cues.beat + 1e-6) + 1, 1, 20), s = String(n).padStart(2, '0');
|
|
331
|
+
text('K', 'SCHLAG', 152, 30, F, 2.6, 'left', 'middle');
|
|
332
|
+
for (let i = 0; i < 2; i++) text('K', s[i], 152 + TYPE.lw + i * TYPE.dw, 30, F, 2.6, 'left', 'middle');
|
|
333
|
+
text('K', '/ 20', 152 + TYPE.lw + 2 * TYPE.dw + 6, 30, F, 2.6, 'left', 'middle');
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function renderPlates(t, opt = {}) {
|
|
338
|
+
CT = [a, b];
|
|
339
|
+
a.setTransform(1, 0, 0, 1, 0, 0); b.setTransform(1, 0, 0, 1, 0, 0);
|
|
340
|
+
a.fillStyle = '#000'; a.fillRect(0, 0, W, H);
|
|
341
|
+
b.fillStyle = '#000'; b.fillRect(0, 0, W, H);
|
|
342
|
+
drawGroup(t, opt);
|
|
343
|
+
drawOuter(t, opt);
|
|
344
|
+
if (!opt.noField) drawField(t);
|
|
345
|
+
drawTitleV5(t);
|
|
346
|
+
drawType(t);
|
|
347
|
+
drawMarks(t);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ---------------------------------------------------------------- WebGL press pass
|
|
351
|
+
const out = document.getElementById('out');
|
|
352
|
+
const gl = out.getContext('webgl2', { preserveDrawingBuffer: true, antialias: false, premultipliedAlpha: false });
|
|
353
|
+
const VS = `#version 300 es
|
|
354
|
+
in vec2 p; void main(){ gl_Position = vec4(p,0.,1.); }`;
|
|
355
|
+
const FS = `#version 300 es
|
|
356
|
+
precision highp float;
|
|
357
|
+
uniform sampler2D tA, tB, tPaper, tGrain, tC, tD;
|
|
358
|
+
uniform float t, frame, slice, casc, resetT, reg, dens0, spread;
|
|
359
|
+
uniform vec3 uCam;
|
|
360
|
+
uniform int taps;
|
|
361
|
+
uniform vec4 uR1, uR2, uR3, uR4; uniform vec2 uR1o;
|
|
362
|
+
uniform float gV[15]; uniform float gH[9]; uniform float wV[15]; uniform float wH[9];
|
|
363
|
+
out vec4 o;
|
|
364
|
+
const vec2 RES = vec2(1920.,1080.);
|
|
365
|
+
const float PI = 3.14159265;
|
|
366
|
+
float h21(vec2 p){ p = fract(p*vec2(123.34, 456.21)); p += dot(p, p+45.32); return fract(p.x*p.y); }
|
|
367
|
+
float vnoise(vec2 p){ vec2 i=floor(p), f=fract(p); f=f*f*(3.-2.*f);
|
|
368
|
+
return mix(mix(h21(i),h21(i+vec2(1,0)),f.x), mix(h21(i+vec2(0,1)),h21(i+vec2(1,1)),f.x), f.y); }
|
|
369
|
+
float ease(float u){ return u<.5 ? 2.*u*u : 1.-pow(-2.*u+2.,2.)*.5; }
|
|
370
|
+
float lineCov(float d, float w){ return clamp(w*.5 + .5 - abs(d), 0., 1.); }
|
|
371
|
+
bool inTrim(vec2 p){ return p.x >= 120. && p.x < 1800. && p.y >= 60. && p.y < 1020.; }
|
|
372
|
+
// Tiling / coverage are computed from the un-offset point q0 (all plates agree on tile membership -> no divergent
|
|
373
|
+
// slivers), the per-plate misregistered point q is only moved within its tile.
|
|
374
|
+
// R1: front 120 tiles turn about their own centres, radial wave from the circle centre
|
|
375
|
+
vec3 rotTile(vec2 q0, vec2 q, float tt){
|
|
376
|
+
if (tt >= resetT || tt < uR1.x || !inTrim(q0)) return vec3(q, 1.);
|
|
377
|
+
vec2 c = vec2(0.,60.) + (floor((q0 - vec2(0.,60.)) / 120.) + .5) * 120.;
|
|
378
|
+
float u = clamp((tt - uR1.x - length(c - uR1o) * uR1.z) / uR1.y, 0., 1.);
|
|
379
|
+
if (u <= 0.) return vec3(q, 1.);
|
|
380
|
+
float th = uR1.w * ease(u);
|
|
381
|
+
float cs = cos(th), sn = sin(th);
|
|
382
|
+
float s = 1. / (abs(cs) + abs(sn));
|
|
383
|
+
vec2 l0 = q0 - c, l = q - c;
|
|
384
|
+
vec2 r0 = vec2(cs*l0.x + sn*l0.y, -sn*l0.x + cs*l0.y) / s;
|
|
385
|
+
vec2 r = vec2(cs*l.x + sn*l.y, -sn*l.x + cs*l.y) / s;
|
|
386
|
+
float gap = smoothstep(0., .035, abs(sin(2.*th))); // sub-pixel gaps (near 0 / 90 deg) are filled, not AA'd to a seam
|
|
387
|
+
float cov = clamp((60. - max(abs(r0.x), abs(r0.y))) * s + .5 + (1. - gap), 0., 1.);
|
|
388
|
+
float turned = min(1., abs(sn) * 20.); // tap clamp only once the tile is really turned
|
|
389
|
+
float lim = 60. - .75 * turned + 4. * (1. - turned);
|
|
390
|
+
return vec3(c + clamp(r, vec2(-lim), vec2(lim)), cov);
|
|
391
|
+
}
|
|
392
|
+
// R3 (r2): back-sheet column PAIRS (240 px) slide one module, alternating up/down, wave right -> left; the label
|
|
393
|
+
// strip (y 840-960) is a static band so GELB 黄 / ROT 红 / BLAU 蓝 never tear
|
|
394
|
+
vec2 slideCol(vec2 q0, vec2 q, float tt){
|
|
395
|
+
if (tt < uR3.x || !inTrim(q0) || (q0.y >= 840. && q0.y < 960.)) return q;
|
|
396
|
+
float col = floor((q0.x - 120.) / 240.);
|
|
397
|
+
float cx = 240. + col * 240.;
|
|
398
|
+
float u = clamp((tt - uR3.x - (1680. - cx) * uR3.z) / uR3.y, 0., 1.);
|
|
399
|
+
if (u <= 0.) return q;
|
|
400
|
+
float dir = mod(col, 2.) < .5 ? -1. : 1.;
|
|
401
|
+
q.x = clamp(q.x, cx - 119.25, cx + 119.25);
|
|
402
|
+
q.y = clamp(q.y - dir * uR3.w * ease(u), 61., 1019.); // no wrap: the card edge rows are black ground
|
|
403
|
+
if (q0.y < 840. && q.y >= 840.) q.y = 839.; // the static strip also masks what slides into it
|
|
404
|
+
if (q0.y >= 960. && q.y < 960.) q.y = 960.;
|
|
405
|
+
return q;
|
|
406
|
+
}
|
|
407
|
+
float face(bool back, vec4 sel, bool isK, vec2 q){
|
|
408
|
+
vec2 uv = q / RES;
|
|
409
|
+
return back ? (isK ? texture(tD, uv).r : dot(texture(tC, uv), sel)) : (isK ? texture(tB, uv).r : dot(texture(tA, uv), sel));
|
|
410
|
+
}
|
|
411
|
+
float gShade; // card face shading of the last inkAt call (0 = flat)
|
|
412
|
+
// one plate's ink at time tt. sel picks the channel (plate A/C rgb) or black (plate B/D r) when isK
|
|
413
|
+
// r2: a turning card is a foreshortened trapezoid (far edge 1-.22|sin|), shaded 1-.2|sin|, over a black press bed
|
|
414
|
+
// mid-turn that becomes the card's own face near rest, so a gap round a card never shows paper.
|
|
415
|
+
float inkAt(vec4 sel, bool isK, vec2 p0, vec2 off, float tt){
|
|
416
|
+
vec2 q0 = p0, q = p0 + off;
|
|
417
|
+
gShade = 0.;
|
|
418
|
+
if (casc > .5 && inTrim(p0)) {
|
|
419
|
+
vec2 c = vec2(120.,60.) + (floor((p0 - vec2(120.,60.)) / 240.) + .5) * 240.;
|
|
420
|
+
float sc; bool ax;
|
|
421
|
+
if (tt < uR4.x) { // R2: cards tumble over their horizontal axis, diagonal wave from the top-left
|
|
422
|
+
float u = clamp((tt - uR2.x - ((c.x - 120.) + (c.y - 60.)) * uR2.z) / uR2.y, 0., 1.);
|
|
423
|
+
sc = cos(PI * ease(u)); ax = false;
|
|
424
|
+
} else { // R4: cards turn home over their vertical axis, converging on the frame centre
|
|
425
|
+
float u = clamp((tt - uR4.x - (uR4.w - length(c - vec2(960.,540.))) * uR4.z) / uR4.y, 0., 1.);
|
|
426
|
+
sc = -cos(PI * ease(u)); ax = true;
|
|
427
|
+
}
|
|
428
|
+
float fB = face(true, sel, isK, slideCol(q0, q, tt));
|
|
429
|
+
vec3 rr = rotTile(q0, q, tt); float fF = face(false, sel, isK, rr.xy) * rr.z;
|
|
430
|
+
float aa = abs(sc), sn = sqrt(max(0., 1. - sc * sc));
|
|
431
|
+
bool back = sc < 0.;
|
|
432
|
+
if (aa > .9995) return back ? fB : fF;
|
|
433
|
+
// board behind the card: mid-turn the cards turn over a BLACK press bed (ink, never paper); near rest the bed
|
|
434
|
+
// becomes the face the card is settling on, so the closing gap is invisible (no paper, no slit)
|
|
435
|
+
float board = mix(isK ? 1. : 0., back ? fB : fF, smoothstep(.72, .96, aa));
|
|
436
|
+
if (aa < .002) return board;
|
|
437
|
+
vec2 l0 = q0 - c, l = q - c;
|
|
438
|
+
float a0 = ax ? l0.x : l0.y, b0 = ax ? l0.y : l0.x, a1 = ax ? l.x : l.y, b1 = ax ? l.y : l.x;
|
|
439
|
+
float ca = clamp(a0 / aa, -120., 120.); // card coordinate along the turning axis
|
|
440
|
+
float fs = ax ? (sc < 0. ? -1. : 1.) : (sc > 0. ? -1. : 1.); // which screen edge is currently the far edge
|
|
441
|
+
float xs = 1. - .22 * sn * (.5 + .5 * fs * ca / 120.); // perspective width at this row
|
|
442
|
+
float cov = clamp(120. * aa - abs(a0) + .5, 0., 1.) * clamp(120. * xs - abs(b0) + .5, 0., 1.);
|
|
443
|
+
float la = clamp(a1 / aa, -119.6, 119.6), lb = clamp(b1 / xs, -119.6, 119.6);
|
|
444
|
+
float la0 = clamp(a0 / aa, -119.6, 119.6), lb0 = clamp(b0 / xs, -119.6, 119.6);
|
|
445
|
+
vec2 cq = c + (ax ? vec2(la, lb) : vec2(lb, la)), cq0 = c + (ax ? vec2(la0, lb0) : vec2(lb0, la0));
|
|
446
|
+
float fv;
|
|
447
|
+
if (back) fv = face(true, sel, isK, slideCol(cq0, cq, tt));
|
|
448
|
+
else { vec3 r = rotTile(cq0, cq, tt); fv = face(false, sel, isK, r.xy) * r.z; }
|
|
449
|
+
gShade = cov * sn;
|
|
450
|
+
return mix(board, fv, cov);
|
|
451
|
+
}
|
|
452
|
+
return face(false, sel, isK, q);
|
|
453
|
+
}
|
|
454
|
+
void main(){
|
|
455
|
+
vec2 p = vec2(gl_FragCoord.x, RES.y - gl_FragCoord.y);
|
|
456
|
+
p = vec2(960., 540.) + (p - vec2(960., 540.)) / uCam.z + uCam.xy; // r2: 7.0 punch (x1.03 -> 1) / 9.5 press jolt
|
|
457
|
+
vec3 paperBase = vec3(241.,233.,218.)/255.;
|
|
458
|
+
float pl = dot(texture(tPaper, p/2600.).rgb, vec3(.333));
|
|
459
|
+
float tooth = pl - .78;
|
|
460
|
+
float big = vnoise(p/340.) - .5;
|
|
461
|
+
vec3 col = paperBase * (1. + tooth*.32 + big*.018);
|
|
462
|
+
vec2 vc = (p/RES - .5); col *= 1. - dot(vc,vc)*.10;
|
|
463
|
+
// ---- grid: each line pair is ruled as a 3px black pen stroke, lands on a 16th, relaxes to the hairline
|
|
464
|
+
float g = 0.;
|
|
465
|
+
for (int i = 0; i < 15; i++) {
|
|
466
|
+
float x = float(i+1)*120.; float on = step(abs(p.y-540.), gV[i]*480.);
|
|
467
|
+
float w = wV[i];
|
|
468
|
+
g = max(g, lineCov(p.x - x, mix(1.1, 3.2, min(w, 1.)) + 2.8 * max(w - 1., 0.)) * on * mix(i==7 ? .28 : .17, .92, min(w, 1.)));
|
|
469
|
+
}
|
|
470
|
+
for (int j = 0; j < 9; j++) {
|
|
471
|
+
float y = 60. + float(j)*120.; float on = step(abs(p.x-960.), gH[j]*960.);
|
|
472
|
+
float w = wH[j];
|
|
473
|
+
g = max(g, lineCov(p.y - y, mix(1.1, 3.2, min(w, 1.)) + 2.8 * max(w - 1., 0.)) * on * mix(j==4 ? .28 : .17, .92, min(w, 1.)));
|
|
474
|
+
}
|
|
475
|
+
// ---- inks: misregistered plates (print space), rough edges, cascade, in-shader temporal taps (motion blur)
|
|
476
|
+
vec2 rough = (vec2(vnoise(p/5.), vnoise(p/5. + 17.3)) - .5) * 1.3 + (vec2(vnoise(p/1.6 + 3.1), vnoise(p/1.6 + 8.7)) - .5) * .35;
|
|
477
|
+
vec2 oY = rough + vec2(spread, 0.), oR = rough + vec2(1.3,-0.9)*reg + vec2(0., spread), oB = rough + vec2(-1.0,1.2)*reg - vec2(0., spread), oK = rough + vec2(0.5,0.4)*reg;
|
|
478
|
+
float mY = 0., mR = 0., mB = 0., mK = 0., shd = 0.;
|
|
479
|
+
for (int i = 0; i < 8; i++) {
|
|
480
|
+
if (i >= taps) break;
|
|
481
|
+
float tt = t + ((float(i) + .5) / float(taps) - .5) * slice;
|
|
482
|
+
mY += inkAt(vec4(1,0,0,0), false, p, oY, tt);
|
|
483
|
+
mR += inkAt(vec4(0,1,0,0), false, p, oR, tt);
|
|
484
|
+
mB += inkAt(vec4(0,0,1,0), false, p, oB, tt);
|
|
485
|
+
mK += inkAt(vec4(0), true, p, oK, tt); shd += gShade;
|
|
486
|
+
}
|
|
487
|
+
float nt = float(taps); mY /= nt; mR /= nt; mB /= nt; mK /= nt; shd /= nt;
|
|
488
|
+
col *= 1. - g*(1. - clamp(max(max(mY,mR),max(mB,mK))*1.2, 0., 1.));
|
|
489
|
+
float mottle = vnoise(p/9.) * .5 + vnoise(p/37.) * .5;
|
|
490
|
+
float dens = clamp(dens0 + .06*(mottle-.5) + tooth*.35, 0., dens0 > 1. ? 1.1 : 1.);
|
|
491
|
+
vec3 Y = vec3(242.,183.,5.)/255., R = vec3(224.,60.,49.)/255., Bl = vec3(30.,79.,163.)/255., K = vec3(17.)/255.;
|
|
492
|
+
col *= mix(vec3(1.), Y/paperBase, mY*dens);
|
|
493
|
+
col *= mix(vec3(1.), R/paperBase, mR*dens);
|
|
494
|
+
col *= mix(vec3(1.), Bl/paperBase, mB*dens);
|
|
495
|
+
col *= mix(vec3(1.), K/paperBase, mK*min(1., dens+.03));
|
|
496
|
+
col *= 1. - .2 * shd; // r2: a turning card's face is shaded (1-.2|sin|)
|
|
497
|
+
col = max(col, vec3(0.));
|
|
498
|
+
vec2 go = vec2(h21(vec2(frame, 1.7)), h21(vec2(frame, 9.1))) * 2048.;
|
|
499
|
+
float gr = texture(tGrain, (p + go)/2048.).r - .5;
|
|
500
|
+
col += gr * .045;
|
|
501
|
+
col += (h21(p + frame) - .5) / 255.;
|
|
502
|
+
o = vec4(col, 1.);
|
|
503
|
+
}`;
|
|
504
|
+
function sh(type, src) { const s = gl.createShader(type); gl.shaderSource(s, src); gl.compileShader(s);
|
|
505
|
+
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(s)); return s; }
|
|
506
|
+
const prog_ = gl.createProgram();
|
|
507
|
+
gl.attachShader(prog_, sh(gl.VERTEX_SHADER, VS)); gl.attachShader(prog_, sh(gl.FRAGMENT_SHADER, FS)); gl.linkProgram(prog_);
|
|
508
|
+
if (!gl.getProgramParameter(prog_, gl.LINK_STATUS)) throw new Error(gl.getProgramInfoLog(prog_));
|
|
509
|
+
gl.useProgram(prog_);
|
|
510
|
+
const vb = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vb);
|
|
511
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
|
|
512
|
+
const loc = gl.getAttribLocation(prog_, 'p'); gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
|
|
513
|
+
const U = n => gl.getUniformLocation(prog_, n);
|
|
514
|
+
function tex(unit, src, repeat) {
|
|
515
|
+
const tx = gl.createTexture(); gl.activeTexture(gl.TEXTURE0 + unit); gl.bindTexture(gl.TEXTURE_2D, tx);
|
|
516
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
517
|
+
const wrap = repeat ? gl.REPEAT : gl.CLAMP_TO_EDGE;
|
|
518
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);
|
|
519
|
+
if (src) gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, src);
|
|
520
|
+
return tx;
|
|
521
|
+
}
|
|
522
|
+
async function img(url) { const i = new Image(); i.src = url; await i.decode(); return i; }
|
|
523
|
+
const [paperImg, grainImg] = await Promise.all([img('/assets/textures/paper/Paper001_4K_color.jpg'), img('/assets/textures/grain/grain_fine_2048.png')]);
|
|
524
|
+
const txA = tex(0, null, false), txB = tex(1, null, false);
|
|
525
|
+
tex(2, paperImg, true); tex(3, grainImg, true);
|
|
526
|
+
gl.uniform1i(U('tA'), 0); gl.uniform1i(U('tB'), 1); gl.uniform1i(U('tPaper'), 2); gl.uniform1i(U('tGrain'), 3);
|
|
527
|
+
gl.uniform1i(U('tC'), 4); gl.uniform1i(U('tD'), 5);
|
|
528
|
+
|
|
529
|
+
// cascade parameters from cues (wave spans normalised by the farthest cell of each ripple)
|
|
530
|
+
{
|
|
531
|
+
const [x0, y0, x1, y1] = cues.trim;
|
|
532
|
+
const r1 = RP.R1, [ox, oy] = r1.origin; let maxD = 1;
|
|
533
|
+
for (let y = y0 + 60; y < y1; y += 120) for (let x = x0 + 60; x < x1; x += 120) maxD = Math.max(maxD, Math.hypot(x - ox, y - oy));
|
|
534
|
+
gl.uniform4f(U('uR1'), r1.start, r1.dur, r1.span / maxD, r1.angle * DEG); gl.uniform2f(U('uR1o'), ox, oy);
|
|
535
|
+
const r2 = RP.R2; gl.uniform4f(U('uR2'), r2.start, r2.dur, r2.span / ((x1 - 120 - x0) + (y1 - 120 - y0)), 0);
|
|
536
|
+
const r3 = RP.R3; gl.uniform4f(U('uR3'), r3.start, r3.dur, r3.span / (1680 - 240), r3.dy);
|
|
537
|
+
const r4 = RP.R4; let mxR = 0, mnR = 1e9;
|
|
538
|
+
for (let y = y0 + 120; y < y1; y += 240) for (let x = x0 + 120; x < x1; x += 240) { const r = Math.hypot(x - CX, y - CY); mxR = Math.max(mxR, r); mnR = Math.min(mnR, r); }
|
|
539
|
+
gl.uniform4f(U('uR4'), r4.start, r4.dur, r4.span / (mxR - mnR), mxR);
|
|
540
|
+
gl.uniform1f(U('resetT'), cues.frontReset);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function gridProg(t) {
|
|
544
|
+
const G = cues.grid, gV = new Float32Array(15), gH = new Float32Array(9), wV = new Float32Array(15), wH = new Float32Array(9);
|
|
545
|
+
const line = (d, arr, warr, i) => { const L = G.land0 + d * G.step; arr[i] = io2(prog(t, L - G.draw, L));
|
|
546
|
+
const pk = d <= 1 ? 2 : 1, rl = d <= 1 ? 8 / 30 : G.relax; // r2 hook: the first 4 axis lines rule at 6 px
|
|
547
|
+
warr[i] = t < L ? (arr[i] > 0 ? pk : 0) : pk * (1 - io2(prog(t, L, L + rl))); };
|
|
548
|
+
for (let i = 0; i < 15; i++) line(Math.abs(i - 7), gV, wV, i);
|
|
549
|
+
for (let j = 0; j < 9; j++) line(Math.abs(j - 4), gH, wH, j);
|
|
550
|
+
return [gV, gH, wV, wH];
|
|
551
|
+
}
|
|
552
|
+
// press (r2): during R2 the plates drift to ~3.5 px, the hero hit (7.0, frame 210) strikes them into register with a
|
|
553
|
+
// 1-frame ink kiss and a x1.03 punch; after the freeze they breathe apart to a 4.5 px Y/R/B spread and the PRESS LOCK
|
|
554
|
+
// (9.5, frame 285) snaps them to register with +10 % ink and a 2 px paper jolt settling over 2 frames.
|
|
555
|
+
function registration(t) {
|
|
556
|
+
const q = snap(t), f = Math.round(t * 30), rv = EV.reveal.t, lock = EV.lock.t, R2 = RP.R2;
|
|
557
|
+
let reg = 1, dens = 0.955, spread = 0;
|
|
558
|
+
if (q >= R2.start && q < rv) reg = 1 + 1.3 * in2(prog(q, R2.start, rv - 1 / 30));
|
|
559
|
+
else if (q >= rv && q < FREEZE) reg = 0.15 + 0.85 * io2(prog(q, RP.R4.start, FREEZE));
|
|
560
|
+
else if (q >= FREEZE && q < lock) { const u = io2(prog(q, FREEZE + 0.5, lock - 1 / 30)); reg = 1 + 0.4 * u; spread = 4.5 * u; }
|
|
561
|
+
if (q >= lock) { reg = 0.12; dens = 0.985; }
|
|
562
|
+
const fr = f - Math.round(rv * 30), fl = f - Math.round(lock * 30);
|
|
563
|
+
if (fr === 0) dens += 0.12; else if (fr === 1) dens += 0.05;
|
|
564
|
+
if (fl === 0) dens += 0.10; else if (fl === 1) dens += 0.04;
|
|
565
|
+
return [reg, dens, spread];
|
|
566
|
+
}
|
|
567
|
+
function camera(t) {
|
|
568
|
+
const f = Math.round(t * 30), fr = f - Math.round(EV.reveal.t * 30), fl = f - Math.round(EV.lock.t * 30);
|
|
569
|
+
const z = fr === 0 ? 1.03 : fr === 1 ? 1.012 : 1;
|
|
570
|
+
const dy = fl === 0 ? 2 : fl === 1 ? 1 : 0;
|
|
571
|
+
return [0, dy, z];
|
|
572
|
+
}
|
|
573
|
+
// shutter 0.5 -> 0.3 while the cards turn (R2 / R4), so a turning card reads as a card, not a smear
|
|
574
|
+
const FLIPS = ['R2', 'R4'].map(k => [RP[k].start, RP[k].start + RP[k].span + RP[k].dur]);
|
|
575
|
+
const shutK = t => { const q = snap(t); return FLIPS.some(([a0, a1]) => q >= a0 && q <= a1) ? 0.6 : 1; };
|
|
576
|
+
// back sheet labels stamp on the hero hit: GELB 黄 7.000 · ROT 红 7.067 · BLAU 蓝 7.133 (frames 210 / 212 / 214)
|
|
577
|
+
let backN = -1, txC = null, txD = null;
|
|
578
|
+
function labelsN(t) { const q = snap(t); return (cues.labels || []).filter(tt => q >= tt - 1e-6).length; }
|
|
579
|
+
|
|
580
|
+
function present(t, k = 1) {
|
|
581
|
+
gl.viewport(0, 0, W, H);
|
|
582
|
+
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, txA); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, cA);
|
|
583
|
+
gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D, txB); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, cB);
|
|
584
|
+
gl.uniform1f(U('t'), t); gl.uniform1f(U('frame'), Math.round(t * 30));
|
|
585
|
+
const on = cascOn(t);
|
|
586
|
+
gl.uniform1f(U('casc'), on ? 1 : 0); gl.uniform1i(U('taps'), on ? 6 : 1);
|
|
587
|
+
gl.uniform1f(U('slice'), k * (window.DEMO.motionBlur.shutter / 30) / MB);
|
|
588
|
+
const nL = labelsN(t);
|
|
589
|
+
if (nL !== backN) { drawBack(nL); backN = nL;
|
|
590
|
+
gl.activeTexture(gl.TEXTURE4); gl.bindTexture(gl.TEXTURE_2D, txC); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, cC);
|
|
591
|
+
gl.activeTexture(gl.TEXTURE5); gl.bindTexture(gl.TEXTURE_2D, txD); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, cD); }
|
|
592
|
+
const cam = camera(t); gl.uniform3f(U('uCam'), cam[0], cam[1], cam[2]);
|
|
593
|
+
const [rg, dn, sp] = registration(t); gl.uniform1f(U('reg'), rg); gl.uniform1f(U('dens0'), dn); gl.uniform1f(U('spread'), sp);
|
|
594
|
+
const [gV, gH, wV, wH] = gridProg(t);
|
|
595
|
+
gl.uniform1fv(U('gV'), gV); gl.uniform1fv(U('gH'), gH); gl.uniform1fv(U('wV'), wV); gl.uniform1fv(U('wH'), wH);
|
|
596
|
+
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
597
|
+
gl.finish();
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
window.renderAt = async (t) => { const tc = snap(t), k = shutK(t); t = tc + (t - tc) * k; renderPlates(t); present(t, k); };
|
|
601
|
+
|
|
602
|
+
// ---------------------------------------------------------------- reel v5: link elements, a pure function of t
|
|
603
|
+
// Positions are in output-frame px: the plate point is moved by that plate's misregistration (the shader samples p + off,
|
|
604
|
+
// so the image sits at -off) and by the press camera (7.0 punch x1.03, 9.5 jolt 2 px).
|
|
605
|
+
const L4 = (() => {
|
|
606
|
+
const [x0, y0, x1, y1] = cues.trim, r1 = RP.R1, [ox, oy] = r1.origin; let maxD = 1, mxR = 0, mnR = 1e9;
|
|
607
|
+
for (let y = y0 + 60; y < y1; y += 120) for (let x = x0 + 60; x < x1; x += 120) maxD = Math.max(maxD, Math.hypot(x - ox, y - oy));
|
|
608
|
+
for (let y = y0 + 120; y < y1; y += 240) for (let x = x0 + 120; x < x1; x += 240) { const r = Math.hypot(x - CX, y - CY); mxR = Math.max(mxR, r); mnR = Math.min(mnR, r); }
|
|
609
|
+
return { ox, oy, z1: r1.span / maxD, z2: RP.R2.span / ((x1 - 120 - x0) + (y1 - 120 - y0)), z3: RP.R3.span / (1680 - 240), z4: RP.R4.span / (mxR - mnR), mxR };
|
|
610
|
+
})();
|
|
611
|
+
const PLATE_OFF = { R: [1.3, -0.9, 0, 1], B: [-1.0, 1.2, 0, -1], Y: [0, 0, 1, 0], K: [0.5, 0.4, 0, 0] }; // reg x, reg y, spread x, spread y
|
|
612
|
+
function toScreen(t, x, y, plate) {
|
|
613
|
+
const [reg, , spread] = registration(t), [cx, cy, z] = camera(t), o = PLATE_OFF[plate];
|
|
614
|
+
const px = x - (o[0] * reg + o[2] * spread) - cx, py = y - (o[1] * reg + o[3] * spread) - cy;
|
|
615
|
+
return [CX + (px - CX) * z, CY + (py - CY) * z, z];
|
|
616
|
+
}
|
|
617
|
+
const r1Ang = (t, x, y) => 90 * io2(clamp((t - RP.R1.start - Math.hypot(x - L4.ox, y - L4.oy) * L4.z1) / RP.R1.dur));
|
|
618
|
+
const r2Cos = (t, x, y) => Math.cos(Math.PI * io2(clamp((t - RP.R2.start - ((x - 120) + (y - 60)) * L4.z2) / RP.R2.dur)));
|
|
619
|
+
const r4Cos = (t, x, y) => -Math.cos(Math.PI * io2(clamp((t - RP.R4.start - (L4.mxR - Math.hypot(x - CX, y - CY)) * L4.z4) / RP.R4.dur)));
|
|
620
|
+
const sstep = (e0, e1, x) => { const u = clamp((x - e0) / (e1 - e0)); return u * u * (3 - 2 * u); };
|
|
621
|
+
const mean = (xs, f) => xs.reduce((s, c) => s + f(c), 0) / xs.length;
|
|
622
|
+
// the front sheet's share of cards at rest (R4 turning home) / the back sheet's share of cards at rest (R2)
|
|
623
|
+
const frontHome = (t, cards) => t < RP.R4.start ? 0 : mean(cards, ([x, y]) => sstep(0.9, 1, r4Cos(t, x, y)));
|
|
624
|
+
const DOT_TILES = [660, 780, 900, 1020].flatMap(x => [120, 240, 360, 480].map(y => [x, y]));
|
|
625
|
+
const DOT_CARDS = [[720, 180], [960, 180], [720, 420], [960, 420]];
|
|
626
|
+
const BAND_CARDS = [480, 720, 960, 1200, 1440, 1680].map(x => [x, 900]);
|
|
627
|
+
const DISC2_CARDS = [[1440, 420], [1680, 420], [1440, 660], [1680, 660]];
|
|
628
|
+
function dotCentre(t) { // red disc, plate coords (group transform applied)
|
|
629
|
+
const e1 = EV.circle_land, u = in2(prog(t, e1.t0, e1.t)), sl = io2(prog(t, EV.circle_slide.t0, EV.circle_slide.t));
|
|
630
|
+
const lx = 840 + (1 - u) * 6 * M, ly = 300 - M * (1 - sl), th = groupAngle(t), c = Math.cos(th), s = Math.sin(th);
|
|
631
|
+
return [CX + c * (lx - CX) - s * (ly - CY), CY + s * (lx - CX) + c * (ly - CY)];
|
|
632
|
+
}
|
|
633
|
+
function dotVis(t) {
|
|
634
|
+
if (t < EV.circle_land.t0) return 0;
|
|
635
|
+
if (!cascOn(t)) return 1;
|
|
636
|
+
if (t < RP.R4.start) return t >= cues.frontReset ? 0 : 1 - clamp(mean(DOT_TILES, ([x, y]) => r1Ang(t, x, y)) / 15); // R1 breaks it
|
|
637
|
+
return frontHome(t, DOT_CARDS); // R4: its 4 cards turn home, whole again on the 8.0 freeze
|
|
638
|
+
}
|
|
639
|
+
function linkAtV5(t) {
|
|
640
|
+
const els = [];
|
|
641
|
+
const [dx, dy, z] = toScreen(t, ...dotCentre(t), 'R');
|
|
642
|
+
els.push({ id: 'dot', type: 'circle', x: +dx.toFixed(1), y: +dy.toFixed(1), r: +(240 * z).toFixed(1), a: +dotVis(t).toFixed(3),
|
|
643
|
+
look: 'grain-flat', fill: '#EB3F33', stroke: '#EB3F33', sw: 0, // fill = measured print colour (ink #E03C31 on cream)
|
|
644
|
+
note: 'Bauhaus red disc Ø480 (primary red ink on cream paper: tooth, mottling, grain, 1-4 px plate misregistration)' });
|
|
645
|
+
// back sheet: the giant blue disc of the ▲■● triad (6.97-7.2 whole; R3 shears it from 7.2)
|
|
646
|
+
if (cascOn(t) && t >= RP.R2.start) {
|
|
647
|
+
let av = t < RP.R4.start ? mean(DISC2_CARDS, ([x, y]) => sstep(0.9, 1, -r2Cos(t, x, y))) : 0;
|
|
648
|
+
const sh = Math.max(...[1440, 1680].map(cx => io2(clamp((t - RP.R3.start - (1680 - cx) * L4.z3) / RP.R3.dur))));
|
|
649
|
+
av *= 1 - clamp(sh * RP.R3.dy / 8);
|
|
650
|
+
const [bx, by, bz] = toScreen(t, 1560, 540, 'B');
|
|
651
|
+
els.push({ id: 'disc2', type: 'circle', x: +bx.toFixed(1), y: +by.toFixed(1), r: +(240 * bz).toFixed(1), a: +av.toFixed(3),
|
|
652
|
+
look: 'grain-flat', fill: '#0942A3', stroke: '#0942A3', sw: 0, note: 'back-sheet blue disc of the giant ▲■● triad, on black' });
|
|
653
|
+
}
|
|
654
|
+
// pivot dot: black point on the horizon at the frame centre (the rotation pivot), stamps at 3.0
|
|
655
|
+
if (snap(t) >= EV.pivot.t && !cascOn(t)) {
|
|
656
|
+
const [px, py, pz] = toScreen(t, CX, CY, 'K');
|
|
657
|
+
els.push({ id: 'pivot', type: 'circle', x: +px.toFixed(1), y: +py.toFixed(1), r: +(20 * pz).toFixed(1), a: 1,
|
|
658
|
+
look: 'grain-flat', fill: '#1C1A12', stroke: '#1C1A12', sw: 0, note: 'black pivot dot on the horizon rule (frame centre)' });
|
|
659
|
+
}
|
|
660
|
+
// horizon rule y 540, ruled 360 -> 1800 over 5.0-5.25; off in the cascade, back on the 8.0 freeze
|
|
661
|
+
if (t >= EV.rule.t0 && !cascOn(t)) {
|
|
662
|
+
const u = io2(prog(t, EV.rule.t0, EV.rule.t)), [x0, y0] = toScreen(t, 360, 540, 'K'), [x1, y1, rz] = toScreen(t, 360 + 1440 * u, 540, 'K');
|
|
663
|
+
els.push({ id: 'rule', type: 'line', x0: +x0.toFixed(1), y0: +y0.toFixed(1), x1: +x1.toFixed(1), y1: +y1.toFixed(1), w: +(6 * rz).toFixed(1),
|
|
664
|
+
a: u > 0.01 ? 1 : 0, fill: '#1C1A12', note: 'horizon rule (6 px black), draws left to right' });
|
|
665
|
+
}
|
|
666
|
+
// black bar: extends 8 modules at 0.75-1.0 (horizontal along the top while the group is turned), swings upright 3.25-4.0
|
|
667
|
+
if (t >= EV.bar_land.t0) {
|
|
668
|
+
const u = in2(prog(t, EV.bar_land.t0, EV.bar_land.t)), th = groupAngle(t), c = Math.cos(th), s = Math.sin(th);
|
|
669
|
+
const R = (x, y) => [CX + c * (x - CX) - s * (y - CY), CY + s * (x - CX) + c * (y - CY)];
|
|
670
|
+
const [ax, ay] = toScreen(t, ...R(1380, 60), 'K'), [bx, by, bz] = toScreen(t, ...R(1380, 60 + 960 * u), 'K');
|
|
671
|
+
els.push({ id: 'bar', type: 'line', x0: +ax.toFixed(1), y0: +ay.toFixed(1), x1: +bx.toFixed(1), y1: +by.toFixed(1), w: +(120 * bz).toFixed(1),
|
|
672
|
+
a: cascOn(t) ? 0 : 1, fill: '#1C1A12', note: 'black bar 120 px wide (centre line); breaks into cards 6.0-8.0' });
|
|
673
|
+
}
|
|
674
|
+
// v5 title block: black bar with 几何构成 (paper) + 包豪斯 (yellow)
|
|
675
|
+
if (titleOn(t)) {
|
|
676
|
+
const [tx, ty, tz] = toScreen(t, (TB.x0 + TB.x1) / 2, (TB.y0 + TB.y1) / 2, 'K');
|
|
677
|
+
els.push({ id: 'title', type: 'rect', x: +tx.toFixed(1), y: +ty.toFixed(1), w: +((TB.x1 - TB.x0) * tz).toFixed(1), h: +((TB.y1 - TB.y0) * tz).toFixed(1), rot: 0,
|
|
678
|
+
a: +(cascOn(t) ? frontHome(t, BAND_CARDS) : 1).toFixed(3), fill: '#1C1A12',
|
|
679
|
+
note: 'title bar 几何构成 · 包豪斯 (x 360-1800, y 780-1020), revealed by the R4 cards, then static' });
|
|
680
|
+
}
|
|
681
|
+
return els;
|
|
682
|
+
}
|
|
683
|
+
if (V5) window.linkAt = linkAtV5;
|
|
684
|
+
|
|
685
|
+
await document.fonts.load(`900 172px "Poppins"`, 'BAUHAUS');
|
|
686
|
+
await document.fonts.load(`600 24px "Poppins"`, 'FORM');
|
|
687
|
+
await document.fonts.load(`600 13px "Poppins"`, 'BOGEN');
|
|
688
|
+
await document.fonts.load(`700 26px "Noto Sans SC"`, '形式色彩功能黄红蓝');
|
|
689
|
+
if (V5) await document.fonts.load(TB.font, '几何构成包豪斯');
|
|
690
|
+
await document.fonts.ready;
|
|
691
|
+
measureType();
|
|
692
|
+
if (V5) measureTitleV5();
|
|
693
|
+
drawBack(0); backN = 0;
|
|
694
|
+
txC = tex(4, cC, false); txD = tex(5, cD, false);
|
|
695
|
+
buildField();
|
|
696
|
+
await window.renderAt(0);
|
|
697
|
+
window.__ready = true;
|