dsh-drawai 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/README.md +7 -5
  2. package/lib/client.js +142 -16
  3. package/lib/index.js +7945 -7719
  4. package/lib/motion/asset-pack.js +394 -394
  5. package/lib/motion/assets.js +291 -291
  6. package/lib/motion/demo-assets-lock.js +10 -10
  7. package/lib/motion/mgstyles/briefs/23-ink-wash.md +147 -0
  8. package/lib/motion/mgstyles/catalog.d/23-ink-wash.json +28 -0
  9. package/lib/motion/mgstyles/catalog.json +127 -14
  10. package/lib/motion/mgstyles/upstream/demos/23-ink-wash/brush.js +149 -0
  11. package/lib/motion/mgstyles/upstream/demos/23-ink-wash/film.js +202 -0
  12. package/lib/motion/mgstyles/upstream/manifest.json +28 -3
  13. package/lib/motion/mgstyles/upstream/prompts/23-ink-wash.md +59 -0
  14. package/lib/motion/mgstyles/vendor/README.md +28 -28
  15. package/lib/motion/mgstyles/vendor/modules/d3/LICENSE +13 -13
  16. package/lib/motion/mgstyles/vendor/modules/d3/dist/d3.min.js +2 -2
  17. package/lib/motion/mgstyles/vendor/modules/opentype.js/LICENSE +20 -20
  18. package/lib/motion/mgstyles/vendor/modules/opentype.js/dist/opentype.mjs +14460 -14460
  19. package/lib/motion/mgstyles/vendor/modules/simplex-noise/LICENSE +21 -21
  20. package/lib/motion/mgstyles/vendor/modules/simplex-noise/dist/esm/simplex-noise.js +465 -465
  21. package/lib/motion/mgstyles/vendor/modules/topojson-client/LICENSE +13 -13
  22. package/lib/motion/mgstyles/vendor/modules/topojson-client/dist/topojson-client.min.js +2 -2
  23. package/lib/motion/project.js +5 -1
  24. package/lib/motion/qa.js +116 -6
  25. package/lib/motion/render.js +179 -179
  26. package/lib/motion/scene-kit.js +1 -1
  27. package/lib/motion/shotcraft/upstream/SKILL.md +286 -286
  28. package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -54
  29. package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -200
  30. package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -45
  31. package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -20
  32. package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -65
  33. package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -151
  34. package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -129
  35. package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -75
  36. package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -40
  37. package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -11
  38. package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -10
  39. package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -49
  40. package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -210
  41. package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -423
  42. package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -170
  43. package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -157
  44. package/lib/motion/shotcraft/upstream/demos/README.md +120 -120
  45. package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -112
  46. package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -647
  47. package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -316
  48. package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -82
  49. package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -115
  50. package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -243
  51. package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +388 -388
  52. package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -250
  53. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -305
  54. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -246
  55. package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -390
  56. package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -138
  57. package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -542
  58. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -315
  59. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -299
  60. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -173
  61. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -348
  62. package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -366
  63. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -279
  64. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -184
  65. package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -390
  66. package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -155
  67. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -303
  68. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -290
  69. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -278
  70. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -307
  71. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -215
  72. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -299
  73. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -232
  74. package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -290
  75. package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -273
  76. package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -167
  77. package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -536
  78. package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -164
  79. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -175
  80. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -197
  81. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -241
  82. package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -279
  83. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -230
  84. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -345
  85. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -275
  86. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -229
  87. package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -312
  88. package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -222
  89. package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -295
  90. package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -329
  91. package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -315
  92. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -264
  93. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -260
  94. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -263
  95. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -123
  96. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -187
  97. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -175
  98. package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -305
  99. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -350
  100. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -352
  101. package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -218
  102. package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -297
  103. package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -157
  104. package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -218
  105. package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -202
  106. package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -265
  107. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -457
  108. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -446
  109. package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -249
  110. package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -278
  111. package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -332
  112. package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -358
  113. package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -201
  114. package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -200
  115. package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -208
  116. package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -341
  117. package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -389
  118. package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -293
  119. package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -183
  120. package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -245
  121. package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -222
  122. package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -223
  123. package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -217
  124. package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -343
  125. package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -357
  126. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -187
  127. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -333
  128. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -274
  129. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -270
  130. package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -430
  131. package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -252
  132. package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -106
  133. package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -288
  134. package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -362
  135. package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -168
  136. package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -310
  137. package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -261
  138. package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -459
  139. package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -294
  140. package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -161
  141. package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -248
  142. package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -359
  143. package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -227
  144. package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -162
  145. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -248
  146. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -186
  147. package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -355
  148. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -272
  149. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -262
  150. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -217
  151. package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -285
  152. package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -205
  153. package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -178
  154. package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -147
  155. package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -143
  156. package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -134
  157. package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -217
  158. package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -198
  159. package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -221
  160. package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -312
  161. package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -261
  162. package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -121
  163. package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -153
  164. package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -179
  165. package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -140
  166. package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -309
  167. package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -191
  168. package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -292
  169. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -135
  170. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -124
  171. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -255
  172. package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -173
  173. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -225
  174. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -141
  175. package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -137
  176. package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -147
  177. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -409
  178. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -280
  179. package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -271
  180. package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -385
  181. package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -312
  182. package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -303
  183. package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -77
  184. package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -311
  185. package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -307
  186. package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -349
  187. package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -255
  188. package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -244
  189. package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -217
  190. package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -652
  191. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -153
  192. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -238
  193. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -324
  194. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -354
  195. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -101
  196. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -129
  197. package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -297
  198. package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -57
  199. package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -155
  200. package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -175
  201. package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -153
  202. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -146
  203. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -226
  204. package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -1
  205. package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -193
  206. package/lib/motion/shotcraft/upstream/references/final-review.md +121 -121
  207. package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -199
  208. package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -183
  209. package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -257
  210. package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -382
  211. package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -111
  212. package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -50
  213. package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -95
  214. package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -41
  215. package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -52
  216. package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -39
  217. package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -39
  218. package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -57
  219. package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -51
  220. package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -46
  221. package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -52
  222. package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -43
  223. package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -42
  224. package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -48
  225. package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -52
  226. package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -45
  227. package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -46
  228. package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -44
  229. package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -63
  230. package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -54
  231. package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -58
  232. package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -35
  233. package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -53
  234. package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -42
  235. package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -50
  236. package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -46
  237. package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -56
  238. package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -49
  239. package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -50
  240. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -53
  241. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -53
  242. package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -55
  243. package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -52
  244. package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -60
  245. package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -57
  246. package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -51
  247. package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -41
  248. package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -53
  249. package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -60
  250. package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -55
  251. package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -57
  252. package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -47
  253. package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -37
  254. package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -54
  255. package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -36
  256. package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -56
  257. package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -56
  258. package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -40
  259. package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -60
  260. package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -57
  261. package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -73
  262. package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -87
  263. package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -55
  264. package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -50
  265. package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -59
  266. package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -38
  267. package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -38
  268. package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -59
  269. package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -39
  270. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -61
  271. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -52
  272. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -50
  273. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -66
  274. package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -43
  275. package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -38
  276. package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -38
  277. package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -56
  278. package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -44
  279. package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -38
  280. package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -63
  281. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -57
  282. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -63
  283. package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -58
  284. package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -45
  285. package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -55
  286. package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -49
  287. package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -42
  288. package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -42
  289. package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -45
  290. package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -48
  291. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -55
  292. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -43
  293. package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -41
  294. package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -42
  295. package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -59
  296. package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -55
  297. package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -65
  298. package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -42
  299. package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -64
  300. package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -64
  301. package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -54
  302. package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -91
  303. package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -51
  304. package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -66
  305. package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -38
  306. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -66
  307. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -58
  308. package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -61
  309. package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -64
  310. package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -45
  311. package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -41
  312. package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -51
  313. package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -42
  314. package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -63
  315. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -57
  316. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -75
  317. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -59
  318. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -67
  319. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -60
  320. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -66
  321. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -40
  322. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -45
  323. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -62
  324. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -55
  325. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -37
  326. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -55
  327. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -50
  328. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -43
  329. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -55
  330. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -51
  331. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -51
  332. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -56
  333. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -49
  334. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -57
  335. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -36
  336. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -64
  337. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -47
  338. package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -170
  339. package/lib/motion/shotcraft/upstream/references/workbench.md +157 -157
  340. package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -103
  341. package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -44
  342. package/lib/motion/shotcraft/upstream/template/package.json +20 -20
  343. package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -6
  344. package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -17
  345. package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -65
  346. package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -48
  347. package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -24
  348. package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -192
  349. package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -111
  350. package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -150
  351. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -158
  352. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -468
  353. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -552
  354. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -411
  355. package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -200
  356. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -324
  357. package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +388 -388
  358. package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -4
  359. package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -7
  360. package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -68
  361. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -1
  362. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -24
  363. package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -74
  364. package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -91
  365. package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -213
  366. package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -15
  367. package/lib/motion/style-frames.js +306 -306
  368. package/lib/motion/sync.js +214 -214
  369. package/lib/motion-library.js +1 -1
  370. package/lib/motion-project.js +105 -105
  371. package/lib/motion-render-worker.js +174 -174
  372. package/lib/routing/router.js +222 -222
  373. package/lib/routing/vendor/README.md +96 -96
  374. package/lib/routing/vendor/libavoid-routing.js +753 -753
  375. package/lib/routing/vendor/libavoid.min.js +59 -59
  376. package/lib/svg-export.js +1344 -0
  377. package/lib/video-trace-pool.js +128 -128
  378. package/package.json +3 -2
  379. package/LICENSE +0 -4175
@@ -1,468 +1,468 @@
1
- import { useVisualTheme, themePaint, themeAsset, sceneDefaults } from '../../themes/visual-theme';
2
- import { Img, interpolate, useCurrentFrame, Easing, getRemotionEnvironment } from 'remotion';
3
- import { PageCam, CamKey } from './PageCam';
4
- import layout from '../live-layout.json';
5
-
6
- const cards = layout.projects.cards;
7
- const PAGE_H = layout.projects.pageH;
8
-
9
- const HOVER_H = 40; // px above the slot (translateZ) a card hovers at mid-dive
10
- const SETTLE_EASE = Easing.bezier(0.3, 0, 0.25, 1.15); // slight overshoot / compress
11
- const DIVE_EASE = Easing.bezier(0.3, 0, 0.2, 1); // decelerate into the hover
12
- const SLIDE_EASE = Easing.bezier(0.35, 0, 0.2, 1); // nano-lab card slide to the top slot
13
-
14
- // page paper colors, sampled from the rendered projects-empty texture
15
-
16
- // ---- 16 "overflow" extras extend the grid DOWNWARD (no hovering, no overlap):
17
- // fill the empty 3rd column of the y=1402 row, then five new rows below the
18
- // texture at y=1795…3367, columns matching the real grid. ----
19
- const COLS = [408, 781.328125, 1154.65625];
20
- const CARD_W = 357.328125;
21
- const EXTRA_ROWS = [1795, 2188, 2581, 2974, 3367];
22
- const PAPER_EXT = { x: 0, y: PAGE_H, w: 1920, h: 2036 }; // paper extension below the texture (flush bottom 3782)
23
-
24
- const extras = Array.from({ length: 16 }, (_, i) => ({
25
- file: `card${((i * 3 + 2) % 10) + 1}.png`, // deterministic, neighbors differ
26
- x: i === 0 ? COLS[2] : COLS[(i - 1) % 3],
27
- y: i === 0 ? 1402 : EXTRA_ROWS[Math.floor((i - 1) / 3)],
28
- w: CARD_W,
29
- h: 312,
30
- title: '',
31
- }));
32
-
33
- // ---- the DECK: all 26 cards start stacked in one pile at the page's top
34
- // right. The shot opens on a rotating 3D close-up of the pile (0–35), pulls
35
- // back to reveal the page (35–62), and the cards deal themselves to their
36
- // slots in reading order (y, then x) on a hard-accelerating cadence — the gap
37
- // between departures shrinks from 4f to 0.2f (gap_k = 4 − 0.1584k), so the
38
- // dealing goes from deliberate to a blur. First departs at 36 (mid pull-back),
39
- // last ≈88, lands ≈96. Pile poses carry a small deterministic jitter and each
40
- // card keeps a stack height (top of pile = first to leave). ----
41
- const PILE = { x: 1430, y: 240 };
42
- const N_CARDS = 26;
43
- const DEAL_START = 36;
44
- const STACK_STEP = 3; // px of physical height per card — the pile reads as a real stack
45
-
46
- // dark-metal backdrop for the opening close-up: covers everything in the page
47
- // plane, with a warm spotlight pooled on the pile; fades out with the pull-back
48
- const METAL_FADE = [34, 56] as const;
49
- // Real-time preview stand-in for the metal (Player / Studio / workbench — anything that is
50
- // not the final render). The procedural gradients below cover a 9000×9000 plane that
51
- // Chromium has to re-rasterize every frame while PageCam's `zoom` changes; in real time
52
- // the raster never keeps up, the plane drops in and out, and the close-up strobes between
53
- // dark table and white page (measured: ~20 blank-outs in the first 2s). A flat fill needs
54
- // no raster at all. Same geometry, same fade — only the paint differs; the render still
55
- // paints the brushed metal. Tone = median of the rendered table (#373637 sampled).
56
-
57
- const grid = [
58
- ...cards.map((c) => ({ file: c.file, x: c.x, y: c.y, w: c.w, h: c.h, title: c.title })),
59
- ...extras,
60
- ]
61
- .sort((a, b) => a.y - b.y || a.x - b.x)
62
- .map((c, k) => ({
63
- ...c,
64
- cue: DEAL_START + 4 * k - 0.0792 * k * (k - 1),
65
- // pile pose: tiny alternating offsets + roll, stacked top-down by k
66
- px: PILE.x + (((k * 7) % 9) - 4) * 2,
67
- py: PILE.y + (((k * 5) % 7) - 3) * 2,
68
- protZ: ((k * 11) % 7) - 3,
69
- pz: (N_CARDS - k) * STACK_STEP, // physical stack height; k=0 rides on top
70
- }));
71
-
72
- // ---- the search target: nano-lab slides up to the first-row slot on filter ----
73
- const nanoIdx = grid.findIndex((c) => c.title.includes('nano-lab'));
74
- const nano = grid[nanoIdx];
75
- const NANO_TO = { x: 408, y: 247 }; // first-row slot the filtered card slides into
76
- const CLICK_C = { x: 586, y: 391 }; // click point on the settled result card
77
-
78
- // filter departure rank for the 19 non-target cards (reading order)
79
- const leaveRank = new Map<number, number>();
80
- grid.forEach((_, i) => {
81
- if (i !== nanoIdx) leaveRank.set(i, leaveRank.size);
82
- });
83
-
84
- // search box (page-space CSS px) + typing beats
85
- const SEARCH = { x: 408, y: 130, w: 1016, h: 44 };
86
- /** Context-level defaults, editable per clip in the workbench. `query` is only the
87
- * typed text; the card that survives the filter is still the nano-lab card from layout. */
88
- export const SCENE_FLYIN_DEFAULTS = {
89
- query: 'nano-lab',
90
- accent: '#ae6700', // oklch(58% 0.13 65)
91
- };
92
- type SceneFlyInProps = Partial<typeof SCENE_FLYIN_DEFAULTS>;
93
- const TYPE_START = 128; // 3 frames per character → last char at ≈149
94
- const FILTER_START = 160; // beat of rest after typing, then the grid filters
95
-
96
- // pile centre for the opening close-up
97
- const PILE_CX = PILE.x + CARD_W / 2;
98
- const PILE_CY = PILE.y + 156;
99
-
100
- // Narrative: the shot opens on a rotating 3D CLOSE-UP of the 26-card pile
101
- // (orbiting from a left-oblique to a right-oblique look), pulls back to
102
- // reveal the page as the pile starts dealing cards to their grid slots, each
103
- // departure faster than the last, extending the grid far below the page fold
104
- // → the camera scrolls down chasing the dealing, FASTER each leg, arriving
105
- // straight at the bottom → rests half a second on the full board → swooshes
106
- // back up to the search box → "nano-lab" is typed (unhurried), a breath, then
107
- // the grid filters down to one card which slides into the first row → a click
108
- // ripple fires and the camera pushes into the card, handing off to detail.
109
- const CAM_KEYS: CamKey[] = [
110
- { frame: 0, cx: PILE_CX - 30, cy: PILE_CY + 60, zoom: 1.95, rotX: 46, rotY: -30, rotZ: 9, persp: 1100 }, // low side view of the stack, left-oblique
111
- { frame: 34, cx: PILE_CX + 30, cy: PILE_CY + 40, zoom: 1.85, rotX: 42, rotY: 26, rotZ: -7, persp: 1100 }, // orbit around the pile to a right-oblique
112
- { frame: 62, cx: 960, cy: 900, zoom: 0.88, rotX: 26, rotY: 0, rotZ: 2, persp: 1300 }, // pull back — dashboard revealed, dealing underway
113
- { frame: 82, cx: 950, cy: 1900, zoom: 0.78, rotX: 14, rotY: 0, rotZ: 0, persp: 1300 }, // speeding up (~50 px/f)
114
- { frame: 98, cx: 960, cy: 3032, zoom: 0.72, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // fastest leg (~70 px/f), arrives straight at the paper's flush bottom
115
- { frame: 113, cx: 960, cy: 3032, zoom: 0.72, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // 0.5s REST on the full board
116
- { frame: 124, cx: 960, cy: 380, zoom: 0.9, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // swoosh back up to the search/filter header
117
- { frame: 174, cx: 960, cy: 380, zoom: 0.9, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // hold through typing, breath, filter, slide
118
- { frame: 190, cx: CLICK_C.x, cy: CLICK_C.y, zoom: 2.2, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // push into the clicked card, carried through the white flash
119
- ];
120
-
121
- export const SceneFlyIn: React.FC<SceneFlyInProps> = (props) => {
122
- const theme = useVisualTheme();
123
- const paperStyle = theme.id === 'ink-press';
124
- const paint = (css: string) => themePaint(theme, css);
125
- const asset = (src: string) => themeAsset(theme, src);
126
- const PAPER = paint('#f9f6f1'); // page background (bottom rows)
127
- const FIELD = paint('#fefcf9'); // search-box interior
128
- const METAL_PREVIEW = paint('#383638');
129
- const { query: QUERY, accent } = { ...sceneDefaults(theme, 'table', SCENE_FLYIN_DEFAULTS), ...props };
130
- const frame = useCurrentFrame();
131
- const { isRendering } = getRemotionEnvironment();
132
-
133
- // DOF fades out over the straightening leg of the scroll (82 → 98)
134
- const dofStrength = interpolate(frame, [82, 98], [5, 0], {
135
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
136
- });
137
-
138
- // typed characters: one every 3 frames from TYPE_START (unhurried typing)
139
- const typedCount = frame < TYPE_START
140
- ? 0
141
- : Math.min(QUERY.length, Math.floor((frame - TYPE_START) / 3) + 1);
142
- // caret: solid while typing, then blinks on an 8-frame cycle until the click
143
- const caretOn =
144
- frame >= TYPE_START - 2 &&
145
- frame <= 185 &&
146
- (frame <= TYPE_START + 24 || Math.floor((frame - (TYPE_START + 24)) / 8) % 2 === 0);
147
-
148
- return (
149
- <PageCam
150
- src="textures/live/projects-empty.png"
151
- pageH={PAGE_H}
152
- keys={CAM_KEYS}
153
- ease={Easing.bezier(0.33, 0, 0.15, 1)}
154
- dof={dofStrength > 0.1 ? { focusY: 260, strength: dofStrength } : undefined}
155
- >
156
- {/* ---- dark brushed-metal table under the opening pile close-up: a huge
157
- plane (covers the viewport at any oblique angle) with a warm
158
- spotlight pooled on the stack; fades away as the camera pulls
159
- back and the dashboard page takes over ---- */}
160
- {frame < METAL_FADE[1] ? (
161
- <div
162
- style={{
163
- position: 'absolute',
164
- left: -3000,
165
- top: -3000,
166
- width: 9000,
167
- height: 9000,
168
- opacity: interpolate(frame, [METAL_FADE[0], METAL_FADE[1]], [1, 0], {
169
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
170
- }),
171
- background: !paperStyle ? theme.stage : isRendering ? [
172
- // warm key light pooled on the pile
173
- paint(`radial-gradient(1300px 900px at ${3000 + PILE_CX}px ${3000 + PILE_CY}px, rgba(255,214,150,0.20), rgba(255,190,120,0.06) 40%, transparent 68%)`),
174
- // brushed-metal grain: fine anisotropic streaks
175
- paint('repeating-linear-gradient(100deg, rgba(255,255,255,0.028) 0px, rgba(255,255,255,0.028) 1px, transparent 2px, transparent 7px)'),
176
- paint('repeating-linear-gradient(100deg, rgba(0,0,0,0.16) 0px, rgba(0,0,0,0.16) 2px, transparent 4px, transparent 13px)'),
177
- // broad steel sheen
178
- paint('linear-gradient(115deg, #2a2d33 0%, #383c44 28%, #22242a 55%, #33363e 78%, #1d1f24 100%)'),
179
- ].join(', ') : METAL_PREVIEW,
180
- pointerEvents: 'none',
181
- }}
182
- />
183
- ) : null}
184
-
185
- {/* ---- paper extension: the page grows past the texture so the three
186
- extra rows sit on paper, not on the void ---- */}
187
- <div
188
- style={{
189
- position: 'absolute',
190
- left: PAPER_EXT.x,
191
- top: PAPER_EXT.y,
192
- width: PAPER_EXT.w,
193
- height: PAPER_EXT.h,
194
- background: PAPER,
195
- pointerEvents: 'none',
196
- }}
197
- />
198
-
199
- {/* ---- filter clean-up: paper patch over the stale section headers /
200
- counts baked into the texture below y=500, revealed 84–92 ---- */}
201
- {frame >= FILTER_START ? (
202
- <div
203
- style={{
204
- position: 'absolute',
205
- left: 0,
206
- top: 500,
207
- width: 1920,
208
- height: PAGE_H - 500,
209
- background: PAPER,
210
- opacity: interpolate(frame, [FILTER_START, FILTER_START + 8], [0, 1], {
211
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
212
- }),
213
- pointerEvents: 'none',
214
- }}
215
- />
216
- ) : null}
217
-
218
- {/* ---- 26 cards: visible pile at top right from frame 0, each card
219
- deals itself to its slot (arc flight, roll resolving) on an
220
- accelerating cadence; on filter the 25 non-matches fade+sink
221
- away and nano-lab slides up to row one ---- */}
222
- {grid.map((c, i) => {
223
- const { cue } = c;
224
- const radius = 16;
225
- const isNano = i === nanoIdx;
226
-
227
- // --- filter fade-out for the 25 non-target cards (staggered, 5f) ---
228
- const outCue = isNano ? Infinity : FILTER_START + leaveRank.get(i)! * 0.4;
229
- if (frame >= outCue + 5) return null;
230
- const outT = isNano
231
- ? 0
232
- : interpolate(frame, [outCue, outCue + 5], [0, 1], {
233
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.inOut(Easing.quad),
234
- });
235
-
236
- // --- beat 1: deal (cue → cue+8): from the pile pose (px,py, stack
237
- // height pz, small roll) to the hover pose over the slot. The flight
238
- // arcs UP first (z bulge) like a card snapped off the top of a deck. ---
239
- const diveT = interpolate(frame, [cue, cue + 8], [0, 1], {
240
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: DIVE_EASE,
241
- });
242
-
243
- // --- beat 2: settle (cue+8 → cue+12): Z from HOVER_H down to 0 ---
244
- const settleT = interpolate(frame, [cue + 8, cue + 12], [0, 1], {
245
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: SETTLE_EASE,
246
- });
247
-
248
- // in-flight pose: pile → slot, roll resolving to 0 by touchdown-hover.
249
- const dx = (c.px - c.x) * (1 - diveT);
250
- const dy = (c.py - c.y) * (1 - diveT);
251
- const rotFlight = c.protZ * (1 - diveT);
252
-
253
- // depth: stack height → arc bulge (+90 at mid-flight) → hover → settle 0.
254
- const arc = Math.sin(diveT * Math.PI) * 90;
255
- const zDive = interpolate(diveT, [0, 1], [c.pz, HOVER_H]) + arc;
256
- const z = frame < cue ? c.pz : zDive * (1 - settleT); // pile height before the deal
257
-
258
- // scale: in the pile 1, snap up 1.06 mid-flight, settle back to 1
259
- const dealScale = 1 + Math.sin(diveT * Math.PI) * 0.06;
260
- const press = interpolate(frame, [cue + 10, cue + 11, cue + 12], [1, 0.996, 1], {
261
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
262
- });
263
- const scale = dealScale * press;
264
-
265
- // --- nano-lab slide (104 → 114): glide from (408,1402) to the first-row
266
- // slot with a light float (scale 1→1.02→1, small Z lift, wider shadow) ---
267
- const slideT = isNano
268
- ? interpolate(frame, [FILTER_START, FILTER_START + 10], [0, 1], {
269
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: SLIDE_EASE,
270
- })
271
- : 0;
272
- const slideDy = (NANO_TO.y - nano.y) * slideT;
273
- const slideDx = (NANO_TO.x - nano.x) * slideT;
274
- const float = Math.sin(slideT * Math.PI); // 0→1→0 across the slide
275
- const slideScale = 1 + 0.02 * float;
276
- const slideZ = 18 * float;
277
-
278
- // once fully settled, force an exact identity so the card sits flush
279
- // with its slot on the tilted board (no residual sub-px drift).
280
- const landed = frame >= cue + 12;
281
- const inPile = frame < cue;
282
- const transform = isNano && frame >= FILTER_START
283
- ? `translate3d(${slideDx}px, ${slideDy}px, ${slideZ}px) scale(${slideScale})`
284
- : outT > 0
285
- ? `translate3d(0px, ${8 * outT}px, 0px)`
286
- : landed
287
- ? 'translate3d(0px, 0px, 0px)'
288
- : inPile
289
- ? `translate3d(${c.px - c.x}px, ${c.py - c.y}px, ${c.pz}px) rotateZ(${c.protZ}deg)`
290
- : `translate3d(${dx}px, ${dy}px, ${z}px) rotateZ(${rotFlight}deg) scale(${scale})`;
291
-
292
- // shadow: stacked cards carry almost none (they sit on each other),
293
- // airborne large/soft, tight when flush, widening on the slide
294
- const shadow = isNano && frame >= FILTER_START
295
- ? paint(`0 ${2 + 14 * float}px ${6 + 26 * float}px rgba(60,45,30,${0.08 + 0.1 * float})`)
296
- : landed
297
- ? paint('0 2px 6px rgba(60,45,30,.08)')
298
- : inPile
299
- ? paint('0 1px 3px rgba(60,45,30,.14)')
300
- : paint(`0 ${36 - 30 * settleT}px ${70 - 60 * settleT}px rgba(60,45,30,${0.3 - 0.22 * settleT})`);
301
-
302
- // motion-blur ghost during the deal: a faint blurred copy trailing the flight path
303
- const showGhost = diveT > 0.02 && diveT < 0.98;
304
- const ghostLagX = (c.px - c.x) * 0.05;
305
- const ghostLagY = (c.py - c.y) * 0.05;
306
-
307
- return (
308
- <div key={`${c.file}-${i}`} style={{ transformStyle: 'preserve-3d' }}>
309
- {showGhost ? (
310
- <div
311
- style={{
312
- position: 'absolute',
313
- left: c.x,
314
- top: c.y,
315
- width: c.w,
316
- height: c.h,
317
- transform: `translate3d(${dx + ghostLagX}px, ${dy + ghostLagY}px, ${z}px) rotateZ(${rotFlight}deg) scale(${scale})`,
318
- transformOrigin: 'center center',
319
- opacity: 0.25 * (1 - diveT),
320
- filter: 'blur(6px)',
321
- borderRadius: radius,
322
- overflow: 'hidden',
323
- pointerEvents: 'none',
324
- }}
325
- >
326
- <Img
327
- src={asset(`textures/live/${c.file}`)}
328
- style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', display: 'block' }}
329
- />
330
- </div>
331
- ) : null}
332
-
333
- <div
334
- style={{
335
- position: 'absolute',
336
- left: c.x,
337
- top: c.y,
338
- width: c.w,
339
- height: c.h,
340
- transform,
341
- transformOrigin: 'center center',
342
- boxShadow: shadow,
343
- borderRadius: radius,
344
- opacity: 1 - outT,
345
- overflow: 'hidden',
346
- }}
347
- >
348
- <Img
349
- src={asset(`textures/live/${c.file}`)}
350
- style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', display: 'block' }}
351
- />
352
- </div>
353
- </div>
354
- );
355
- })}
356
-
357
- {/* ---- search box: paper patch over the placeholder text (keeps the
358
- magnifier icon), then "nano-lab" typed in with a blinking caret ---- */}
359
- {frame >= 118 ? (
360
- <div
361
- style={{
362
- position: 'absolute',
363
- left: 440,
364
- top: SEARCH.y + 4,
365
- width: SEARCH.x + SEARCH.w - 448,
366
- height: SEARCH.h - 8,
367
- background: FIELD,
368
- opacity: interpolate(frame, [118, 124], [0, 1], {
369
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
370
- }),
371
- pointerEvents: 'none',
372
- }}
373
- />
374
- ) : null}
375
- {frame >= TYPE_START - 2 ? (
376
- <div
377
- style={{
378
- position: 'absolute',
379
- left: 448,
380
- top: SEARCH.y,
381
- height: SEARCH.h,
382
- display: 'flex',
383
- alignItems: 'center',
384
- fontFamily: (paperStyle ? 'ui-sans-serif, system-ui, -apple-system, sans-serif' : theme.font),
385
- fontSize: 15,
386
- letterSpacing: 0.2,
387
- color: paint('oklch(25% 0.006 82)'),
388
- pointerEvents: 'none',
389
- }}
390
- >
391
- <span>{QUERY.slice(0, typedCount)}</span>
392
- {caretOn ? (
393
- <span
394
- style={{
395
- display: 'inline-block',
396
- width: 2,
397
- height: 20,
398
- marginLeft: 2,
399
- background: accent,
400
- }}
401
- />
402
- ) : null}
403
- </div>
404
- ) : null}
405
-
406
- {/* ---- click ripple on the filtered card: two concentric amber rings ---- */}
407
- {[0, 1].map((r) => {
408
- const start = 176 + r * 3;
409
- if (frame < start || frame > start + 10) return null;
410
- const t = interpolate(frame, [start, start + 10], [0, 1], {
411
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.out(Easing.cubic),
412
- });
413
- const rad = interpolate(t, [0, 1], [14, r === 0 ? 54 : 78]);
414
- return (
415
- <div
416
- key={`ripple-${r}`}
417
- style={{
418
- position: 'absolute',
419
- left: CLICK_C.x - rad,
420
- top: CLICK_C.y - rad,
421
- width: rad * 2,
422
- height: rad * 2,
423
- borderRadius: '50%',
424
- border: `2px solid ${accent}`,
425
- opacity: 1 - t,
426
- pointerEvents: 'none',
427
- }}
428
- />
429
- );
430
- })}
431
-
432
- {/* ---- selected-card amber outline, lit from the click until the cut ---- */}
433
- {frame >= 178 ? (
434
- <div
435
- style={{
436
- position: 'absolute',
437
- left: NANO_TO.x - 6,
438
- top: NANO_TO.y - 6,
439
- width: nano.w + 12,
440
- height: nano.h + 12,
441
- borderRadius: 16,
442
- border: `3px solid ${accent}`,
443
- boxShadow: paint('0 0 40px rgba(180,120,50,0.5)'),
444
- opacity: interpolate(frame, [178, 181], [0.5, 1], {
445
- extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
446
- }),
447
- pointerEvents: 'none',
448
- }}
449
- />
450
- ) : null}
451
-
452
- {/* near-edge rim light along the extended board's leading (bottom) edge */}
453
- <div
454
- style={{
455
- position: 'absolute',
456
- left: 0,
457
- right: 0,
458
- top: PAPER_EXT.y + PAPER_EXT.h - 8,
459
- height: 8,
460
- background: paint('rgba(255,255,255,0.85)'),
461
- filter: 'blur(6px)',
462
- opacity: 0.5,
463
- pointerEvents: 'none',
464
- }}
465
- />
466
- </PageCam>
467
- );
468
- };
1
+ import { useVisualTheme, themePaint, themeAsset, sceneDefaults } from '../../themes/visual-theme';
2
+ import { Img, interpolate, useCurrentFrame, Easing, getRemotionEnvironment } from 'remotion';
3
+ import { PageCam, CamKey } from './PageCam';
4
+ import layout from '../live-layout.json';
5
+
6
+ const cards = layout.projects.cards;
7
+ const PAGE_H = layout.projects.pageH;
8
+
9
+ const HOVER_H = 40; // px above the slot (translateZ) a card hovers at mid-dive
10
+ const SETTLE_EASE = Easing.bezier(0.3, 0, 0.25, 1.15); // slight overshoot / compress
11
+ const DIVE_EASE = Easing.bezier(0.3, 0, 0.2, 1); // decelerate into the hover
12
+ const SLIDE_EASE = Easing.bezier(0.35, 0, 0.2, 1); // nano-lab card slide to the top slot
13
+
14
+ // page paper colors, sampled from the rendered projects-empty texture
15
+
16
+ // ---- 16 "overflow" extras extend the grid DOWNWARD (no hovering, no overlap):
17
+ // fill the empty 3rd column of the y=1402 row, then five new rows below the
18
+ // texture at y=1795…3367, columns matching the real grid. ----
19
+ const COLS = [408, 781.328125, 1154.65625];
20
+ const CARD_W = 357.328125;
21
+ const EXTRA_ROWS = [1795, 2188, 2581, 2974, 3367];
22
+ const PAPER_EXT = { x: 0, y: PAGE_H, w: 1920, h: 2036 }; // paper extension below the texture (flush bottom 3782)
23
+
24
+ const extras = Array.from({ length: 16 }, (_, i) => ({
25
+ file: `card${((i * 3 + 2) % 10) + 1}.png`, // deterministic, neighbors differ
26
+ x: i === 0 ? COLS[2] : COLS[(i - 1) % 3],
27
+ y: i === 0 ? 1402 : EXTRA_ROWS[Math.floor((i - 1) / 3)],
28
+ w: CARD_W,
29
+ h: 312,
30
+ title: '',
31
+ }));
32
+
33
+ // ---- the DECK: all 26 cards start stacked in one pile at the page's top
34
+ // right. The shot opens on a rotating 3D close-up of the pile (0–35), pulls
35
+ // back to reveal the page (35–62), and the cards deal themselves to their
36
+ // slots in reading order (y, then x) on a hard-accelerating cadence — the gap
37
+ // between departures shrinks from 4f to 0.2f (gap_k = 4 − 0.1584k), so the
38
+ // dealing goes from deliberate to a blur. First departs at 36 (mid pull-back),
39
+ // last ≈88, lands ≈96. Pile poses carry a small deterministic jitter and each
40
+ // card keeps a stack height (top of pile = first to leave). ----
41
+ const PILE = { x: 1430, y: 240 };
42
+ const N_CARDS = 26;
43
+ const DEAL_START = 36;
44
+ const STACK_STEP = 3; // px of physical height per card — the pile reads as a real stack
45
+
46
+ // dark-metal backdrop for the opening close-up: covers everything in the page
47
+ // plane, with a warm spotlight pooled on the pile; fades out with the pull-back
48
+ const METAL_FADE = [34, 56] as const;
49
+ // Real-time preview stand-in for the metal (Player / Studio / workbench — anything that is
50
+ // not the final render). The procedural gradients below cover a 9000×9000 plane that
51
+ // Chromium has to re-rasterize every frame while PageCam's `zoom` changes; in real time
52
+ // the raster never keeps up, the plane drops in and out, and the close-up strobes between
53
+ // dark table and white page (measured: ~20 blank-outs in the first 2s). A flat fill needs
54
+ // no raster at all. Same geometry, same fade — only the paint differs; the render still
55
+ // paints the brushed metal. Tone = median of the rendered table (#373637 sampled).
56
+
57
+ const grid = [
58
+ ...cards.map((c) => ({ file: c.file, x: c.x, y: c.y, w: c.w, h: c.h, title: c.title })),
59
+ ...extras,
60
+ ]
61
+ .sort((a, b) => a.y - b.y || a.x - b.x)
62
+ .map((c, k) => ({
63
+ ...c,
64
+ cue: DEAL_START + 4 * k - 0.0792 * k * (k - 1),
65
+ // pile pose: tiny alternating offsets + roll, stacked top-down by k
66
+ px: PILE.x + (((k * 7) % 9) - 4) * 2,
67
+ py: PILE.y + (((k * 5) % 7) - 3) * 2,
68
+ protZ: ((k * 11) % 7) - 3,
69
+ pz: (N_CARDS - k) * STACK_STEP, // physical stack height; k=0 rides on top
70
+ }));
71
+
72
+ // ---- the search target: nano-lab slides up to the first-row slot on filter ----
73
+ const nanoIdx = grid.findIndex((c) => c.title.includes('nano-lab'));
74
+ const nano = grid[nanoIdx];
75
+ const NANO_TO = { x: 408, y: 247 }; // first-row slot the filtered card slides into
76
+ const CLICK_C = { x: 586, y: 391 }; // click point on the settled result card
77
+
78
+ // filter departure rank for the 19 non-target cards (reading order)
79
+ const leaveRank = new Map<number, number>();
80
+ grid.forEach((_, i) => {
81
+ if (i !== nanoIdx) leaveRank.set(i, leaveRank.size);
82
+ });
83
+
84
+ // search box (page-space CSS px) + typing beats
85
+ const SEARCH = { x: 408, y: 130, w: 1016, h: 44 };
86
+ /** Context-level defaults, editable per clip in the workbench. `query` is only the
87
+ * typed text; the card that survives the filter is still the nano-lab card from layout. */
88
+ export const SCENE_FLYIN_DEFAULTS = {
89
+ query: 'nano-lab',
90
+ accent: '#ae6700', // oklch(58% 0.13 65)
91
+ };
92
+ type SceneFlyInProps = Partial<typeof SCENE_FLYIN_DEFAULTS>;
93
+ const TYPE_START = 128; // 3 frames per character → last char at ≈149
94
+ const FILTER_START = 160; // beat of rest after typing, then the grid filters
95
+
96
+ // pile centre for the opening close-up
97
+ const PILE_CX = PILE.x + CARD_W / 2;
98
+ const PILE_CY = PILE.y + 156;
99
+
100
+ // Narrative: the shot opens on a rotating 3D CLOSE-UP of the 26-card pile
101
+ // (orbiting from a left-oblique to a right-oblique look), pulls back to
102
+ // reveal the page as the pile starts dealing cards to their grid slots, each
103
+ // departure faster than the last, extending the grid far below the page fold
104
+ // → the camera scrolls down chasing the dealing, FASTER each leg, arriving
105
+ // straight at the bottom → rests half a second on the full board → swooshes
106
+ // back up to the search box → "nano-lab" is typed (unhurried), a breath, then
107
+ // the grid filters down to one card which slides into the first row → a click
108
+ // ripple fires and the camera pushes into the card, handing off to detail.
109
+ const CAM_KEYS: CamKey[] = [
110
+ { frame: 0, cx: PILE_CX - 30, cy: PILE_CY + 60, zoom: 1.95, rotX: 46, rotY: -30, rotZ: 9, persp: 1100 }, // low side view of the stack, left-oblique
111
+ { frame: 34, cx: PILE_CX + 30, cy: PILE_CY + 40, zoom: 1.85, rotX: 42, rotY: 26, rotZ: -7, persp: 1100 }, // orbit around the pile to a right-oblique
112
+ { frame: 62, cx: 960, cy: 900, zoom: 0.88, rotX: 26, rotY: 0, rotZ: 2, persp: 1300 }, // pull back — dashboard revealed, dealing underway
113
+ { frame: 82, cx: 950, cy: 1900, zoom: 0.78, rotX: 14, rotY: 0, rotZ: 0, persp: 1300 }, // speeding up (~50 px/f)
114
+ { frame: 98, cx: 960, cy: 3032, zoom: 0.72, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // fastest leg (~70 px/f), arrives straight at the paper's flush bottom
115
+ { frame: 113, cx: 960, cy: 3032, zoom: 0.72, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // 0.5s REST on the full board
116
+ { frame: 124, cx: 960, cy: 380, zoom: 0.9, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // swoosh back up to the search/filter header
117
+ { frame: 174, cx: 960, cy: 380, zoom: 0.9, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // hold through typing, breath, filter, slide
118
+ { frame: 190, cx: CLICK_C.x, cy: CLICK_C.y, zoom: 2.2, rotX: 0, rotY: 0, rotZ: 0, persp: 1300 }, // push into the clicked card, carried through the white flash
119
+ ];
120
+
121
+ export const SceneFlyIn: React.FC<SceneFlyInProps> = (props) => {
122
+ const theme = useVisualTheme();
123
+ const paperStyle = theme.id === 'ink-press';
124
+ const paint = (css: string) => themePaint(theme, css);
125
+ const asset = (src: string) => themeAsset(theme, src);
126
+ const PAPER = paint('#f9f6f1'); // page background (bottom rows)
127
+ const FIELD = paint('#fefcf9'); // search-box interior
128
+ const METAL_PREVIEW = paint('#383638');
129
+ const { query: QUERY, accent } = { ...sceneDefaults(theme, 'table', SCENE_FLYIN_DEFAULTS), ...props };
130
+ const frame = useCurrentFrame();
131
+ const { isRendering } = getRemotionEnvironment();
132
+
133
+ // DOF fades out over the straightening leg of the scroll (82 → 98)
134
+ const dofStrength = interpolate(frame, [82, 98], [5, 0], {
135
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
136
+ });
137
+
138
+ // typed characters: one every 3 frames from TYPE_START (unhurried typing)
139
+ const typedCount = frame < TYPE_START
140
+ ? 0
141
+ : Math.min(QUERY.length, Math.floor((frame - TYPE_START) / 3) + 1);
142
+ // caret: solid while typing, then blinks on an 8-frame cycle until the click
143
+ const caretOn =
144
+ frame >= TYPE_START - 2 &&
145
+ frame <= 185 &&
146
+ (frame <= TYPE_START + 24 || Math.floor((frame - (TYPE_START + 24)) / 8) % 2 === 0);
147
+
148
+ return (
149
+ <PageCam
150
+ src="textures/live/projects-empty.png"
151
+ pageH={PAGE_H}
152
+ keys={CAM_KEYS}
153
+ ease={Easing.bezier(0.33, 0, 0.15, 1)}
154
+ dof={dofStrength > 0.1 ? { focusY: 260, strength: dofStrength } : undefined}
155
+ >
156
+ {/* ---- dark brushed-metal table under the opening pile close-up: a huge
157
+ plane (covers the viewport at any oblique angle) with a warm
158
+ spotlight pooled on the stack; fades away as the camera pulls
159
+ back and the dashboard page takes over ---- */}
160
+ {frame < METAL_FADE[1] ? (
161
+ <div
162
+ style={{
163
+ position: 'absolute',
164
+ left: -3000,
165
+ top: -3000,
166
+ width: 9000,
167
+ height: 9000,
168
+ opacity: interpolate(frame, [METAL_FADE[0], METAL_FADE[1]], [1, 0], {
169
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
170
+ }),
171
+ background: !paperStyle ? theme.stage : isRendering ? [
172
+ // warm key light pooled on the pile
173
+ paint(`radial-gradient(1300px 900px at ${3000 + PILE_CX}px ${3000 + PILE_CY}px, rgba(255,214,150,0.20), rgba(255,190,120,0.06) 40%, transparent 68%)`),
174
+ // brushed-metal grain: fine anisotropic streaks
175
+ paint('repeating-linear-gradient(100deg, rgba(255,255,255,0.028) 0px, rgba(255,255,255,0.028) 1px, transparent 2px, transparent 7px)'),
176
+ paint('repeating-linear-gradient(100deg, rgba(0,0,0,0.16) 0px, rgba(0,0,0,0.16) 2px, transparent 4px, transparent 13px)'),
177
+ // broad steel sheen
178
+ paint('linear-gradient(115deg, #2a2d33 0%, #383c44 28%, #22242a 55%, #33363e 78%, #1d1f24 100%)'),
179
+ ].join(', ') : METAL_PREVIEW,
180
+ pointerEvents: 'none',
181
+ }}
182
+ />
183
+ ) : null}
184
+
185
+ {/* ---- paper extension: the page grows past the texture so the three
186
+ extra rows sit on paper, not on the void ---- */}
187
+ <div
188
+ style={{
189
+ position: 'absolute',
190
+ left: PAPER_EXT.x,
191
+ top: PAPER_EXT.y,
192
+ width: PAPER_EXT.w,
193
+ height: PAPER_EXT.h,
194
+ background: PAPER,
195
+ pointerEvents: 'none',
196
+ }}
197
+ />
198
+
199
+ {/* ---- filter clean-up: paper patch over the stale section headers /
200
+ counts baked into the texture below y=500, revealed 84–92 ---- */}
201
+ {frame >= FILTER_START ? (
202
+ <div
203
+ style={{
204
+ position: 'absolute',
205
+ left: 0,
206
+ top: 500,
207
+ width: 1920,
208
+ height: PAGE_H - 500,
209
+ background: PAPER,
210
+ opacity: interpolate(frame, [FILTER_START, FILTER_START + 8], [0, 1], {
211
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
212
+ }),
213
+ pointerEvents: 'none',
214
+ }}
215
+ />
216
+ ) : null}
217
+
218
+ {/* ---- 26 cards: visible pile at top right from frame 0, each card
219
+ deals itself to its slot (arc flight, roll resolving) on an
220
+ accelerating cadence; on filter the 25 non-matches fade+sink
221
+ away and nano-lab slides up to row one ---- */}
222
+ {grid.map((c, i) => {
223
+ const { cue } = c;
224
+ const radius = 16;
225
+ const isNano = i === nanoIdx;
226
+
227
+ // --- filter fade-out for the 25 non-target cards (staggered, 5f) ---
228
+ const outCue = isNano ? Infinity : FILTER_START + leaveRank.get(i)! * 0.4;
229
+ if (frame >= outCue + 5) return null;
230
+ const outT = isNano
231
+ ? 0
232
+ : interpolate(frame, [outCue, outCue + 5], [0, 1], {
233
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.inOut(Easing.quad),
234
+ });
235
+
236
+ // --- beat 1: deal (cue → cue+8): from the pile pose (px,py, stack
237
+ // height pz, small roll) to the hover pose over the slot. The flight
238
+ // arcs UP first (z bulge) like a card snapped off the top of a deck. ---
239
+ const diveT = interpolate(frame, [cue, cue + 8], [0, 1], {
240
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: DIVE_EASE,
241
+ });
242
+
243
+ // --- beat 2: settle (cue+8 → cue+12): Z from HOVER_H down to 0 ---
244
+ const settleT = interpolate(frame, [cue + 8, cue + 12], [0, 1], {
245
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: SETTLE_EASE,
246
+ });
247
+
248
+ // in-flight pose: pile → slot, roll resolving to 0 by touchdown-hover.
249
+ const dx = (c.px - c.x) * (1 - diveT);
250
+ const dy = (c.py - c.y) * (1 - diveT);
251
+ const rotFlight = c.protZ * (1 - diveT);
252
+
253
+ // depth: stack height → arc bulge (+90 at mid-flight) → hover → settle 0.
254
+ const arc = Math.sin(diveT * Math.PI) * 90;
255
+ const zDive = interpolate(diveT, [0, 1], [c.pz, HOVER_H]) + arc;
256
+ const z = frame < cue ? c.pz : zDive * (1 - settleT); // pile height before the deal
257
+
258
+ // scale: in the pile 1, snap up 1.06 mid-flight, settle back to 1
259
+ const dealScale = 1 + Math.sin(diveT * Math.PI) * 0.06;
260
+ const press = interpolate(frame, [cue + 10, cue + 11, cue + 12], [1, 0.996, 1], {
261
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
262
+ });
263
+ const scale = dealScale * press;
264
+
265
+ // --- nano-lab slide (104 → 114): glide from (408,1402) to the first-row
266
+ // slot with a light float (scale 1→1.02→1, small Z lift, wider shadow) ---
267
+ const slideT = isNano
268
+ ? interpolate(frame, [FILTER_START, FILTER_START + 10], [0, 1], {
269
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: SLIDE_EASE,
270
+ })
271
+ : 0;
272
+ const slideDy = (NANO_TO.y - nano.y) * slideT;
273
+ const slideDx = (NANO_TO.x - nano.x) * slideT;
274
+ const float = Math.sin(slideT * Math.PI); // 0→1→0 across the slide
275
+ const slideScale = 1 + 0.02 * float;
276
+ const slideZ = 18 * float;
277
+
278
+ // once fully settled, force an exact identity so the card sits flush
279
+ // with its slot on the tilted board (no residual sub-px drift).
280
+ const landed = frame >= cue + 12;
281
+ const inPile = frame < cue;
282
+ const transform = isNano && frame >= FILTER_START
283
+ ? `translate3d(${slideDx}px, ${slideDy}px, ${slideZ}px) scale(${slideScale})`
284
+ : outT > 0
285
+ ? `translate3d(0px, ${8 * outT}px, 0px)`
286
+ : landed
287
+ ? 'translate3d(0px, 0px, 0px)'
288
+ : inPile
289
+ ? `translate3d(${c.px - c.x}px, ${c.py - c.y}px, ${c.pz}px) rotateZ(${c.protZ}deg)`
290
+ : `translate3d(${dx}px, ${dy}px, ${z}px) rotateZ(${rotFlight}deg) scale(${scale})`;
291
+
292
+ // shadow: stacked cards carry almost none (they sit on each other),
293
+ // airborne large/soft, tight when flush, widening on the slide
294
+ const shadow = isNano && frame >= FILTER_START
295
+ ? paint(`0 ${2 + 14 * float}px ${6 + 26 * float}px rgba(60,45,30,${0.08 + 0.1 * float})`)
296
+ : landed
297
+ ? paint('0 2px 6px rgba(60,45,30,.08)')
298
+ : inPile
299
+ ? paint('0 1px 3px rgba(60,45,30,.14)')
300
+ : paint(`0 ${36 - 30 * settleT}px ${70 - 60 * settleT}px rgba(60,45,30,${0.3 - 0.22 * settleT})`);
301
+
302
+ // motion-blur ghost during the deal: a faint blurred copy trailing the flight path
303
+ const showGhost = diveT > 0.02 && diveT < 0.98;
304
+ const ghostLagX = (c.px - c.x) * 0.05;
305
+ const ghostLagY = (c.py - c.y) * 0.05;
306
+
307
+ return (
308
+ <div key={`${c.file}-${i}`} style={{ transformStyle: 'preserve-3d' }}>
309
+ {showGhost ? (
310
+ <div
311
+ style={{
312
+ position: 'absolute',
313
+ left: c.x,
314
+ top: c.y,
315
+ width: c.w,
316
+ height: c.h,
317
+ transform: `translate3d(${dx + ghostLagX}px, ${dy + ghostLagY}px, ${z}px) rotateZ(${rotFlight}deg) scale(${scale})`,
318
+ transformOrigin: 'center center',
319
+ opacity: 0.25 * (1 - diveT),
320
+ filter: 'blur(6px)',
321
+ borderRadius: radius,
322
+ overflow: 'hidden',
323
+ pointerEvents: 'none',
324
+ }}
325
+ >
326
+ <Img
327
+ src={asset(`textures/live/${c.file}`)}
328
+ style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', display: 'block' }}
329
+ />
330
+ </div>
331
+ ) : null}
332
+
333
+ <div
334
+ style={{
335
+ position: 'absolute',
336
+ left: c.x,
337
+ top: c.y,
338
+ width: c.w,
339
+ height: c.h,
340
+ transform,
341
+ transformOrigin: 'center center',
342
+ boxShadow: shadow,
343
+ borderRadius: radius,
344
+ opacity: 1 - outT,
345
+ overflow: 'hidden',
346
+ }}
347
+ >
348
+ <Img
349
+ src={asset(`textures/live/${c.file}`)}
350
+ style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', display: 'block' }}
351
+ />
352
+ </div>
353
+ </div>
354
+ );
355
+ })}
356
+
357
+ {/* ---- search box: paper patch over the placeholder text (keeps the
358
+ magnifier icon), then "nano-lab" typed in with a blinking caret ---- */}
359
+ {frame >= 118 ? (
360
+ <div
361
+ style={{
362
+ position: 'absolute',
363
+ left: 440,
364
+ top: SEARCH.y + 4,
365
+ width: SEARCH.x + SEARCH.w - 448,
366
+ height: SEARCH.h - 8,
367
+ background: FIELD,
368
+ opacity: interpolate(frame, [118, 124], [0, 1], {
369
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
370
+ }),
371
+ pointerEvents: 'none',
372
+ }}
373
+ />
374
+ ) : null}
375
+ {frame >= TYPE_START - 2 ? (
376
+ <div
377
+ style={{
378
+ position: 'absolute',
379
+ left: 448,
380
+ top: SEARCH.y,
381
+ height: SEARCH.h,
382
+ display: 'flex',
383
+ alignItems: 'center',
384
+ fontFamily: (paperStyle ? 'ui-sans-serif, system-ui, -apple-system, sans-serif' : theme.font),
385
+ fontSize: 15,
386
+ letterSpacing: 0.2,
387
+ color: paint('oklch(25% 0.006 82)'),
388
+ pointerEvents: 'none',
389
+ }}
390
+ >
391
+ <span>{QUERY.slice(0, typedCount)}</span>
392
+ {caretOn ? (
393
+ <span
394
+ style={{
395
+ display: 'inline-block',
396
+ width: 2,
397
+ height: 20,
398
+ marginLeft: 2,
399
+ background: accent,
400
+ }}
401
+ />
402
+ ) : null}
403
+ </div>
404
+ ) : null}
405
+
406
+ {/* ---- click ripple on the filtered card: two concentric amber rings ---- */}
407
+ {[0, 1].map((r) => {
408
+ const start = 176 + r * 3;
409
+ if (frame < start || frame > start + 10) return null;
410
+ const t = interpolate(frame, [start, start + 10], [0, 1], {
411
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.out(Easing.cubic),
412
+ });
413
+ const rad = interpolate(t, [0, 1], [14, r === 0 ? 54 : 78]);
414
+ return (
415
+ <div
416
+ key={`ripple-${r}`}
417
+ style={{
418
+ position: 'absolute',
419
+ left: CLICK_C.x - rad,
420
+ top: CLICK_C.y - rad,
421
+ width: rad * 2,
422
+ height: rad * 2,
423
+ borderRadius: '50%',
424
+ border: `2px solid ${accent}`,
425
+ opacity: 1 - t,
426
+ pointerEvents: 'none',
427
+ }}
428
+ />
429
+ );
430
+ })}
431
+
432
+ {/* ---- selected-card amber outline, lit from the click until the cut ---- */}
433
+ {frame >= 178 ? (
434
+ <div
435
+ style={{
436
+ position: 'absolute',
437
+ left: NANO_TO.x - 6,
438
+ top: NANO_TO.y - 6,
439
+ width: nano.w + 12,
440
+ height: nano.h + 12,
441
+ borderRadius: 16,
442
+ border: `3px solid ${accent}`,
443
+ boxShadow: paint('0 0 40px rgba(180,120,50,0.5)'),
444
+ opacity: interpolate(frame, [178, 181], [0.5, 1], {
445
+ extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
446
+ }),
447
+ pointerEvents: 'none',
448
+ }}
449
+ />
450
+ ) : null}
451
+
452
+ {/* near-edge rim light along the extended board's leading (bottom) edge */}
453
+ <div
454
+ style={{
455
+ position: 'absolute',
456
+ left: 0,
457
+ right: 0,
458
+ top: PAPER_EXT.y + PAPER_EXT.h - 8,
459
+ height: 8,
460
+ background: paint('rgba(255,255,255,0.85)'),
461
+ filter: 'blur(6px)',
462
+ opacity: 0.5,
463
+ pointerEvents: 'none',
464
+ }}
465
+ />
466
+ </PageCam>
467
+ );
468
+ };