@vgai/engine 0.2.0 → 0.3.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/README.md +3 -1
- package/dist/adapter/authoring.d.ts +404 -0
- package/dist/adapter/authoring.d.ts.map +1 -0
- package/dist/adapter/authoring.js +22 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts +43 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -0
- package/dist/adapter/colyseus-networking-adapter.js +38 -0
- package/dist/adapter/first-party-systems.d.ts +38 -0
- package/dist/adapter/first-party-systems.d.ts.map +1 -0
- package/dist/adapter/first-party-systems.js +77 -0
- package/dist/adapter/game-adapter.d.ts +133 -0
- package/dist/adapter/game-adapter.d.ts.map +1 -0
- package/dist/adapter/game-adapter.js +10 -0
- package/dist/adapter/host-context.d.ts +73 -0
- package/dist/adapter/host-context.d.ts.map +1 -0
- package/dist/adapter/host-context.js +16 -0
- package/dist/adapter/index.d.ts +22 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +15 -0
- package/dist/adapter/ingest/game-contract.d.ts +53 -0
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -0
- package/dist/adapter/ingest/game-contract.js +30 -0
- package/dist/adapter/ingest/overlay-applier.d.ts +118 -0
- package/dist/adapter/ingest/overlay-applier.d.ts.map +1 -0
- package/dist/adapter/ingest/overlay-applier.js +132 -0
- package/dist/adapter/ingest/overlay-apply.d.ts +60 -0
- package/dist/adapter/ingest/overlay-apply.d.ts.map +1 -0
- package/dist/adapter/ingest/overlay-apply.js +101 -0
- package/dist/adapter/ingest/overlay-file.d.ts +79 -0
- package/dist/adapter/ingest/overlay-file.d.ts.map +1 -0
- package/dist/adapter/ingest/overlay-file.js +66 -0
- package/dist/adapter/ingest/overlay-report.d.ts +113 -0
- package/dist/adapter/ingest/overlay-report.d.ts.map +1 -0
- package/dist/adapter/ingest/overlay-report.js +103 -0
- package/dist/adapter/ingest/scene-capture.d.ts +97 -0
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -0
- package/dist/adapter/ingest/scene-capture.js +248 -0
- package/dist/adapter/ingest/upstream-pin.d.ts +47 -0
- package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -0
- package/dist/adapter/ingest/upstream-pin.js +50 -0
- package/dist/adapter/loop-gate-report.d.ts +34 -0
- package/dist/adapter/loop-gate-report.d.ts.map +1 -0
- package/dist/adapter/loop-gate-report.js +37 -0
- package/dist/adapter/rapier-physics-adapter.d.ts +12 -0
- package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -0
- package/dist/adapter/rapier-physics-adapter.js +46 -0
- package/dist/adapter/system-adapter.d.ts +133 -0
- package/dist/adapter/system-adapter.d.ts.map +1 -0
- package/dist/adapter/system-adapter.js +13 -0
- package/dist/adapter/transform.d.ts +18 -0
- package/dist/adapter/transform.d.ts.map +1 -0
- package/dist/adapter/transform.js +1 -0
- package/dist/adapter/vgai-scene-game-adapter.d.ts +116 -0
- package/dist/adapter/vgai-scene-game-adapter.d.ts.map +1 -0
- package/dist/adapter/vgai-scene-game-adapter.js +714 -0
- package/dist/adapter/world-kind.d.ts +30 -0
- package/dist/adapter/world-kind.d.ts.map +1 -0
- package/dist/adapter/world-kind.js +18 -0
- package/dist/ai/navigation.d.ts +64 -0
- package/dist/ai/navigation.d.ts.map +1 -0
- package/dist/ai/navigation.js +133 -0
- package/dist/animation/anim-graph-types.d.ts +25 -0
- package/dist/animation/anim-graph-types.d.ts.map +1 -0
- package/dist/animation/anim-graph-types.js +1 -0
- package/dist/animation/animation-clock.d.ts +213 -0
- package/dist/animation/animation-clock.d.ts.map +1 -0
- package/dist/animation/animation-clock.js +301 -0
- package/dist/animation/blend-node.d.ts +22 -0
- package/dist/animation/blend-node.d.ts.map +1 -0
- package/dist/animation/blend-node.js +97 -0
- package/dist/animation/camera-ownership.d.ts +250 -0
- package/dist/animation/camera-ownership.d.ts.map +1 -0
- package/dist/animation/camera-ownership.js +169 -0
- package/dist/animation/cinematic-cues.d.ts +200 -0
- package/dist/animation/cinematic-cues.d.ts.map +1 -0
- package/dist/animation/cinematic-cues.js +213 -0
- package/dist/animation/clip-map.d.ts +12 -0
- package/dist/animation/clip-map.d.ts.map +1 -0
- package/dist/animation/clip-map.js +37 -0
- package/dist/animation/gsap-registration.d.ts +119 -0
- package/dist/animation/gsap-registration.d.ts.map +1 -0
- package/dist/animation/gsap-registration.js +92 -0
- package/dist/animation/theatre-clock-binding.d.ts +89 -0
- package/dist/animation/theatre-clock-binding.d.ts.map +1 -0
- package/dist/animation/theatre-clock-binding.js +29 -0
- package/dist/animation/theatre-director.d.ts +242 -0
- package/dist/animation/theatre-director.d.ts.map +1 -0
- package/dist/animation/theatre-director.js +235 -0
- package/dist/animation/theatre-object-binding.d.ts +305 -0
- package/dist/animation/theatre-object-binding.d.ts.map +1 -0
- package/dist/animation/theatre-object-binding.js +351 -0
- package/dist/animation/xstate-animation-binding.d.ts +111 -0
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -0
- package/dist/animation/xstate-animation-binding.js +307 -0
- package/dist/animation/xstate-animation-meta.d.ts +228 -0
- package/dist/animation/xstate-animation-meta.d.ts.map +1 -0
- package/dist/animation/xstate-animation-meta.js +221 -0
- package/dist/assets.d.ts +26 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +55 -0
- package/dist/audio/index.d.ts +4 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +24 -0
- package/dist/audio/tone-clock-binding.d.ts +75 -0
- package/dist/audio/tone-clock-binding.d.ts.map +1 -0
- package/dist/audio/tone-clock-binding.js +29 -0
- package/dist/audio/tone-context.d.ts +114 -0
- package/dist/audio/tone-context.d.ts.map +1 -0
- package/dist/audio/tone-context.js +39 -0
- package/dist/audio/tone-offline-render.d.ts +90 -0
- package/dist/audio/tone-offline-render.d.ts.map +1 -0
- package/dist/audio/tone-offline-render.js +56 -0
- package/dist/audio/wav-encode.d.ts +38 -0
- package/dist/audio/wav-encode.d.ts.map +1 -0
- package/dist/audio/wav-encode.js +97 -0
- package/dist/core/game-loop.d.ts +21 -0
- package/dist/core/game-loop.d.ts.map +1 -0
- package/dist/core/game-loop.js +130 -0
- package/dist/core/system-runner.d.ts +120 -0
- package/dist/core/system-runner.d.ts.map +1 -0
- package/dist/core/system-runner.js +286 -0
- package/dist/core/types.d.ts +58 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +25 -0
- package/dist/data/data-asset.d.ts +101 -0
- package/dist/data/data-asset.d.ts.map +1 -0
- package/dist/data/data-asset.js +122 -0
- package/dist/data/data-check-core.d.ts +110 -0
- package/dist/data/data-check-core.d.ts.map +1 -0
- package/dist/data/data-check-core.js +178 -0
- package/dist/data/data-ref.d.ts +79 -0
- package/dist/data/data-ref.d.ts.map +1 -0
- package/dist/data/data-ref.js +130 -0
- package/dist/data/vite-plugin-data.d.ts +79 -0
- package/dist/data/vite-plugin-data.d.ts.map +1 -0
- package/dist/data/vite-plugin-data.js +217 -0
- package/dist/dev/console-bridge.d.ts +22 -0
- package/dist/dev/console-bridge.d.ts.map +1 -0
- package/dist/dev/console-bridge.js +71 -0
- package/dist/dev/debug-draw.d.ts +24 -0
- package/dist/dev/debug-draw.d.ts.map +1 -0
- package/dist/dev/debug-draw.js +73 -0
- package/dist/dev/logger.d.ts +30 -0
- package/dist/dev/logger.d.ts.map +1 -0
- package/dist/dev/logger.js +90 -0
- package/dist/ecs/component-manager.d.ts +189 -0
- package/dist/ecs/component-manager.d.ts.map +1 -0
- package/dist/ecs/component-manager.js +676 -0
- package/dist/ecs/game-component.d.ts +97 -0
- package/dist/ecs/game-component.d.ts.map +1 -0
- package/dist/ecs/game-component.js +80 -0
- package/dist/ecs/hmr-swap-report.d.ts +53 -0
- package/dist/ecs/hmr-swap-report.d.ts.map +1 -0
- package/dist/ecs/hmr-swap-report.js +55 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/input/input-manager.d.ts +596 -0
- package/dist/input/input-manager.d.ts.map +1 -0
- package/dist/input/input-manager.js +1564 -0
- package/dist/input/input-types.d.ts +171 -0
- package/dist/input/input-types.d.ts.map +1 -0
- package/dist/input/input-types.js +1 -0
- package/dist/input/prompt-labels.d.ts +21 -0
- package/dist/input/prompt-labels.d.ts.map +1 -0
- package/dist/input/prompt-labels.js +121 -0
- package/dist/input/rebind-controller.d.ts +59 -0
- package/dist/input/rebind-controller.d.ts.map +1 -0
- package/dist/input/rebind-controller.js +85 -0
- package/dist/input/schema.d.ts +16 -0
- package/dist/input/schema.d.ts.map +1 -0
- package/dist/input/schema.js +228 -0
- package/dist/loader.d.ts +43 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +59 -0
- package/dist/manifest/index.d.ts +5 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +8 -0
- package/dist/manifest/load-file.d.ts +4 -0
- package/dist/manifest/load-file.d.ts.map +1 -0
- package/dist/manifest/load-file.js +14 -0
- package/dist/manifest/load.d.ts +117 -0
- package/dist/manifest/load.d.ts.map +1 -0
- package/dist/manifest/load.js +255 -0
- package/dist/manifest/schema.d.ts +173 -0
- package/dist/manifest/schema.d.ts.map +1 -0
- package/dist/manifest/schema.js +302 -0
- package/dist/physics/collision-system.d.ts +41 -0
- package/dist/physics/collision-system.d.ts.map +1 -0
- package/dist/physics/collision-system.js +64 -0
- package/dist/physics/physics-registry.d.ts +45 -0
- package/dist/physics/physics-registry.d.ts.map +1 -0
- package/dist/physics/physics-registry.js +65 -0
- package/dist/physics/transform-writer.d.ts +16 -0
- package/dist/physics/transform-writer.d.ts.map +1 -0
- package/dist/physics/transform-writer.js +38 -0
- package/dist/physics/trigger-dispatch.d.ts +24 -0
- package/dist/physics/trigger-dispatch.d.ts.map +1 -0
- package/dist/physics/trigger-dispatch.js +80 -0
- package/dist/react/game-state.d.ts +105 -0
- package/dist/react/game-state.d.ts.map +1 -0
- package/dist/react/game-state.js +144 -0
- package/dist/react/use-data.d.ts +60 -0
- package/dist/react/use-data.d.ts.map +1 -0
- package/dist/react/use-data.js +96 -0
- package/dist/react/use-selection.d.ts +75 -0
- package/dist/react/use-selection.d.ts.map +1 -0
- package/dist/react/use-selection.js +90 -0
- package/dist/render/auto-batcher.d.ts +34 -0
- package/dist/render/auto-batcher.d.ts.map +1 -0
- package/dist/render/auto-batcher.js +140 -0
- package/dist/render/render-batch-system.d.ts +33 -0
- package/dist/render/render-batch-system.d.ts.map +1 -0
- package/dist/render/render-batch-system.js +230 -0
- package/dist/render/render-features.d.ts +47 -0
- package/dist/render/render-features.d.ts.map +1 -0
- package/dist/render/render-features.js +105 -0
- package/dist/render/render-settings.d.ts +36 -0
- package/dist/render/render-settings.d.ts.map +1 -0
- package/dist/render/render-settings.js +51 -0
- package/dist/runtime/create-runtime.d.ts +280 -0
- package/dist/runtime/create-runtime.d.ts.map +1 -0
- package/dist/runtime/create-runtime.js +795 -0
- package/dist/runtime/frame-selector-cache.d.ts +41 -0
- package/dist/runtime/frame-selector-cache.d.ts.map +1 -0
- package/dist/runtime/frame-selector-cache.js +65 -0
- package/dist/runtime/game.d.ts +433 -0
- package/dist/runtime/game.d.ts.map +1 -0
- package/dist/runtime/game.js +569 -0
- package/dist/runtime/input-router.d.ts +78 -0
- package/dist/runtime/input-router.d.ts.map +1 -0
- package/dist/runtime/input-router.js +171 -0
- package/dist/runtime/mount-game.d.ts +129 -0
- package/dist/runtime/mount-game.d.ts.map +1 -0
- package/dist/runtime/mount-game.js +152 -0
- package/dist/runtime/mount-manifest.d.ts +119 -0
- package/dist/runtime/mount-manifest.d.ts.map +1 -0
- package/dist/runtime/mount-manifest.js +204 -0
- package/dist/runtime/render-audio-control.d.ts +110 -0
- package/dist/runtime/render-audio-control.d.ts.map +1 -0
- package/dist/runtime/render-audio-control.js +111 -0
- package/dist/runtime/render-control.d.ts +291 -0
- package/dist/runtime/render-control.d.ts.map +1 -0
- package/dist/runtime/render-control.js +264 -0
- package/dist/runtime/render-seed.d.ts +57 -0
- package/dist/runtime/render-seed.d.ts.map +1 -0
- package/dist/runtime/render-seed.js +74 -0
- package/dist/runtime/scene-ui-bridge.d.ts +69 -0
- package/dist/runtime/scene-ui-bridge.d.ts.map +1 -0
- package/dist/runtime/scene-ui-bridge.js +23 -0
- package/dist/runtime/scene-ui-data.d.ts +13 -0
- package/dist/runtime/scene-ui-data.d.ts.map +1 -0
- package/dist/runtime/scene-ui-data.js +92 -0
- package/dist/runtime/state-bridge.d.ts +47 -0
- package/dist/runtime/state-bridge.d.ts.map +1 -0
- package/dist/runtime/state-bridge.js +53 -0
- package/dist/runtime/types.d.ts +179 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/scene/asset-loaders.d.ts +79 -0
- package/dist/scene/asset-loaders.d.ts.map +1 -0
- package/dist/scene/asset-loaders.js +141 -0
- package/dist/scene/asset-paths.d.ts +11 -0
- package/dist/scene/asset-paths.d.ts.map +1 -0
- package/dist/scene/asset-paths.js +108 -0
- package/dist/scene/asset-ref-check.d.ts +88 -0
- package/dist/scene/asset-ref-check.d.ts.map +1 -0
- package/dist/scene/asset-ref-check.js +214 -0
- package/dist/scene/asset-registry.d.ts +30 -0
- package/dist/scene/asset-registry.d.ts.map +1 -0
- package/dist/scene/asset-registry.js +50 -0
- package/dist/scene/collider-dimensions.d.ts +63 -0
- package/dist/scene/collider-dimensions.d.ts.map +1 -0
- package/dist/scene/collider-dimensions.js +98 -0
- package/dist/scene/component-registry.d.ts +17 -0
- package/dist/scene/component-registry.d.ts.map +1 -0
- package/dist/scene/component-registry.js +28 -0
- package/dist/scene/defaults.d.ts +252 -0
- package/dist/scene/defaults.d.ts.map +1 -0
- package/dist/scene/defaults.js +151 -0
- package/dist/scene/geometries/index.d.ts +8 -0
- package/dist/scene/geometries/index.d.ts.map +1 -0
- package/dist/scene/geometries/index.js +7 -0
- package/dist/scene/geometries/terrain.d.ts +2 -0
- package/dist/scene/geometries/terrain.d.ts.map +1 -0
- package/dist/scene/geometries/terrain.js +37 -0
- package/dist/scene/geometry-registry.d.ts +24 -0
- package/dist/scene/geometry-registry.d.ts.map +1 -0
- package/dist/scene/geometry-registry.js +20 -0
- package/dist/scene/instance-registry.d.ts +36 -0
- package/dist/scene/instance-registry.d.ts.map +1 -0
- package/dist/scene/instance-registry.js +55 -0
- package/dist/scene/instancers/grid.d.ts +2 -0
- package/dist/scene/instancers/grid.d.ts.map +1 -0
- package/dist/scene/instancers/grid.js +36 -0
- package/dist/scene/instancers/index.d.ts +8 -0
- package/dist/scene/instancers/index.d.ts.map +1 -0
- package/dist/scene/instancers/index.js +7 -0
- package/dist/scene/light-camera-factory.d.ts +23 -0
- package/dist/scene/light-camera-factory.d.ts.map +1 -0
- package/dist/scene/light-camera-factory.js +68 -0
- package/dist/scene/material-factory.d.ts +17 -0
- package/dist/scene/material-factory.d.ts.map +1 -0
- package/dist/scene/material-factory.js +197 -0
- package/dist/scene/material-registry.d.ts +40 -0
- package/dist/scene/material-registry.d.ts.map +1 -0
- package/dist/scene/material-registry.js +44 -0
- package/dist/scene/materials/index.d.ts +8 -0
- package/dist/scene/materials/index.d.ts.map +1 -0
- package/dist/scene/materials/index.js +7 -0
- package/dist/scene/materials/water.d.ts +2 -0
- package/dist/scene/materials/water.d.ts.map +1 -0
- package/dist/scene/materials/water.js +54 -0
- package/dist/scene/parse.d.ts +23 -0
- package/dist/scene/parse.d.ts.map +1 -0
- package/dist/scene/parse.js +179 -0
- package/dist/scene/particles-factory.d.ts +33 -0
- package/dist/scene/particles-factory.d.ts.map +1 -0
- package/dist/scene/particles-factory.js +282 -0
- package/dist/scene/scene-apply.d.ts +109 -0
- package/dist/scene/scene-apply.d.ts.map +1 -0
- package/dist/scene/scene-apply.js +326 -0
- package/dist/scene/scene-diff-schema.d.ts +285 -0
- package/dist/scene/scene-diff-schema.d.ts.map +1 -0
- package/dist/scene/scene-diff-schema.js +92 -0
- package/dist/scene/scene-diff-types.d.ts +40 -0
- package/dist/scene/scene-diff-types.d.ts.map +1 -0
- package/dist/scene/scene-diff-types.js +14 -0
- package/dist/scene/scene-loader.d.ts +177 -0
- package/dist/scene/scene-loader.d.ts.map +1 -0
- package/dist/scene/scene-loader.js +1213 -0
- package/dist/scene/scene-query.d.ts +11 -0
- package/dist/scene/scene-query.d.ts.map +1 -0
- package/dist/scene/scene-query.js +63 -0
- package/dist/scene/scene-types.d.ts +10 -0
- package/dist/scene/scene-types.d.ts.map +1 -0
- package/dist/scene/scene-types.js +8 -0
- package/dist/scene/scene-version.d.ts +26 -0
- package/dist/scene/scene-version.d.ts.map +1 -0
- package/dist/scene/scene-version.js +34 -0
- package/dist/scene/schema/animation.d.ts +8 -0
- package/dist/scene/schema/animation.d.ts.map +1 -0
- package/dist/scene/schema/animation.js +42 -0
- package/dist/scene/schema/audio.d.ts +13 -0
- package/dist/scene/schema/audio.d.ts.map +1 -0
- package/dist/scene/schema/audio.js +22 -0
- package/dist/scene/schema/camera.d.ts +28 -0
- package/dist/scene/schema/camera.d.ts.map +1 -0
- package/dist/scene/schema/camera.js +17 -0
- package/dist/scene/schema/collider.d.ts +40 -0
- package/dist/scene/schema/collider.d.ts.map +1 -0
- package/dist/scene/schema/collider.js +55 -0
- package/dist/scene/schema/entity-ref.d.ts +31 -0
- package/dist/scene/schema/entity-ref.d.ts.map +1 -0
- package/dist/scene/schema/entity-ref.js +61 -0
- package/dist/scene/schema/entity.d.ts +1036 -0
- package/dist/scene/schema/entity.d.ts.map +1 -0
- package/dist/scene/schema/entity.js +153 -0
- package/dist/scene/schema/environment.d.ts +425 -0
- package/dist/scene/schema/environment.d.ts.map +1 -0
- package/dist/scene/schema/environment.js +357 -0
- package/dist/scene/schema/index.d.ts +39 -0
- package/dist/scene/schema/index.d.ts.map +1 -0
- package/dist/scene/schema/index.js +20 -0
- package/dist/scene/schema/instances.d.ts +14 -0
- package/dist/scene/schema/instances.d.ts.map +1 -0
- package/dist/scene/schema/instances.js +28 -0
- package/dist/scene/schema/joint.d.ts +23 -0
- package/dist/scene/schema/joint.d.ts.map +1 -0
- package/dist/scene/schema/joint.js +23 -0
- package/dist/scene/schema/light.d.ts +38 -0
- package/dist/scene/schema/light.d.ts.map +1 -0
- package/dist/scene/schema/light.js +26 -0
- package/dist/scene/schema/material.d.ts +199 -0
- package/dist/scene/schema/material.d.ts.map +1 -0
- package/dist/scene/schema/material.js +99 -0
- package/dist/scene/schema/mesh.d.ts +48 -0
- package/dist/scene/schema/mesh.d.ts.map +1 -0
- package/dist/scene/schema/mesh.js +82 -0
- package/dist/scene/schema/particles.d.ts +2178 -0
- package/dist/scene/schema/particles.d.ts.map +1 -0
- package/dist/scene/schema/particles.js +321 -0
- package/dist/scene/schema/physics.d.ts +56 -0
- package/dist/scene/schema/physics.d.ts.map +1 -0
- package/dist/scene/schema/physics.js +37 -0
- package/dist/scene/schema/scene-file.d.ts +304 -0
- package/dist/scene/schema/scene-file.d.ts.map +1 -0
- package/dist/scene/schema/scene-file.js +262 -0
- package/dist/scene/schema/shadow.d.ts +28 -0
- package/dist/scene/schema/shadow.d.ts.map +1 -0
- package/dist/scene/schema/shadow.js +20 -0
- package/dist/scene/schema/spline.d.ts +25 -0
- package/dist/scene/schema/spline.d.ts.map +1 -0
- package/dist/scene/schema/spline.js +15 -0
- package/dist/scene/schema/tuples.d.ts +12 -0
- package/dist/scene/schema/tuples.d.ts.map +1 -0
- package/dist/scene/schema/tuples.js +14 -0
- package/dist/scene/schema/ui.d.ts +880 -0
- package/dist/scene/schema/ui.d.ts.map +1 -0
- package/dist/scene/schema/ui.js +506 -0
- package/dist/scene/user-data.d.ts +171 -0
- package/dist/scene/user-data.d.ts.map +1 -0
- package/dist/scene/user-data.js +137 -0
- package/dist/setup/setup-audio.d.ts +20 -0
- package/dist/setup/setup-audio.d.ts.map +1 -0
- package/dist/setup/setup-audio.js +41 -0
- package/dist/setup/setup-particles.d.ts +17 -0
- package/dist/setup/setup-particles.d.ts.map +1 -0
- package/dist/setup/setup-particles.js +16 -0
- package/dist/setup/setup-physics.d.ts +25 -0
- package/dist/setup/setup-physics.d.ts.map +1 -0
- package/dist/setup/setup-physics.js +51 -0
- package/dist/setup/setup-renderer.d.ts +69 -0
- package/dist/setup/setup-renderer.d.ts.map +1 -0
- package/dist/setup/setup-renderer.js +363 -0
- package/dist/tools/define-tool.d.ts +105 -0
- package/dist/tools/define-tool.d.ts.map +1 -0
- package/dist/tools/define-tool.js +82 -0
- package/dist/world2d/authoring-2d.d.ts +76 -0
- package/dist/world2d/authoring-2d.d.ts.map +1 -0
- package/dist/world2d/authoring-2d.js +176 -0
- package/dist/world2d/capture-to-scene2d.d.ts +5 -0
- package/dist/world2d/capture-to-scene2d.d.ts.map +1 -0
- package/dist/world2d/capture-to-scene2d.js +49 -0
- package/dist/world2d/collision-2d.d.ts +52 -0
- package/dist/world2d/collision-2d.d.ts.map +1 -0
- package/dist/world2d/collision-2d.js +70 -0
- package/dist/world2d/components-2d.d.ts +47 -0
- package/dist/world2d/components-2d.d.ts.map +1 -0
- package/dist/world2d/components-2d.js +77 -0
- package/dist/world2d/index.d.ts +34 -0
- package/dist/world2d/index.d.ts.map +1 -0
- package/dist/world2d/index.js +32 -0
- package/dist/world2d/ingest-iframe-2d.d.ts +82 -0
- package/dist/world2d/ingest-iframe-2d.d.ts.map +1 -0
- package/dist/world2d/ingest-iframe-2d.js +166 -0
- package/dist/world2d/ingest2d.d.ts +97 -0
- package/dist/world2d/ingest2d.d.ts.map +1 -0
- package/dist/world2d/ingest2d.js +40 -0
- package/dist/world2d/physics2d-registry.d.ts +24 -0
- package/dist/world2d/physics2d-registry.d.ts.map +1 -0
- package/dist/world2d/physics2d-registry.js +38 -0
- package/dist/world2d/pixi-game-adapter.d.ts +107 -0
- package/dist/world2d/pixi-game-adapter.d.ts.map +1 -0
- package/dist/world2d/pixi-game-adapter.js +211 -0
- package/dist/world2d/pixi-surface.d.ts +39 -0
- package/dist/world2d/pixi-surface.d.ts.map +1 -0
- package/dist/world2d/pixi-surface.js +47 -0
- package/dist/world2d/scene-capture-2d.d.ts +43 -0
- package/dist/world2d/scene-capture-2d.d.ts.map +1 -0
- package/dist/world2d/scene-capture-2d.js +92 -0
- package/dist/world2d/scene2d-loader.d.ts +27 -0
- package/dist/world2d/scene2d-loader.d.ts.map +1 -0
- package/dist/world2d/scene2d-loader.js +274 -0
- package/dist/world2d/schema/entity2d.d.ts +102 -0
- package/dist/world2d/schema/entity2d.d.ts.map +1 -0
- package/dist/world2d/schema/entity2d.js +119 -0
- package/dist/world2d/schema/physics2d.d.ts +46 -0
- package/dist/world2d/schema/physics2d.d.ts.map +1 -0
- package/dist/world2d/schema/physics2d.js +45 -0
- package/dist/world2d/schema/sprite.d.ts +42 -0
- package/dist/world2d/schema/sprite.d.ts.map +1 -0
- package/dist/world2d/schema/sprite.js +63 -0
- package/dist/world2d/schema/tilemap.d.ts +15 -0
- package/dist/world2d/schema/tilemap.d.ts.map +1 -0
- package/dist/world2d/schema/tilemap.js +19 -0
- package/dist/world2d/schema/tuples2d.d.ts +20 -0
- package/dist/world2d/schema/tuples2d.d.ts.map +1 -0
- package/dist/world2d/schema/tuples2d.js +19 -0
- package/dist/world2d/system-adapters-2d.d.ts +16 -0
- package/dist/world2d/system-adapters-2d.d.ts.map +1 -0
- package/dist/world2d/system-adapters-2d.js +37 -0
- package/dist/world2d/transform-writer-2d.d.ts +16 -0
- package/dist/world2d/transform-writer-2d.d.ts.map +1 -0
- package/dist/world2d/transform-writer-2d.js +22 -0
- package/dist/world2d/types.d.ts +53 -0
- package/dist/world2d/types.d.ts.map +1 -0
- package/dist/world2d/types.js +1 -0
- package/package.json +18 -4
- package/src/adapter/authoring.ts +10 -0
- package/src/adapter/first-party-systems.ts +23 -34
- package/src/adapter/index.ts +1 -3
- package/src/adapter/system-adapter.ts +15 -22
- package/src/adapter/vgai-scene-game-adapter.ts +5 -14
- package/src/animation/anim-graph-types.ts +12 -43
- package/src/animation/animation-clock.ts +479 -0
- package/src/animation/camera-ownership.ts +467 -0
- package/src/animation/cinematic-cues.ts +451 -0
- package/src/animation/clip-map.ts +41 -0
- package/src/animation/gsap-registration.ts +184 -0
- package/src/animation/theatre-clock-binding.ts +111 -0
- package/src/animation/theatre-director.ts +347 -0
- package/src/animation/theatre-object-binding.ts +661 -0
- package/src/animation/xstate-animation-binding.ts +398 -0
- package/src/animation/xstate-animation-meta.ts +282 -0
- package/src/audio/index.ts +39 -7
- package/src/audio/tone-clock-binding.ts +98 -0
- package/src/audio/tone-context.ts +129 -0
- package/src/audio/tone-offline-render.ts +167 -0
- package/src/audio/wav-encode.ts +119 -0
- package/src/core/game-loop.ts +17 -0
- package/src/core/types.ts +13 -0
- package/src/data/data-asset.ts +167 -0
- package/src/data/data-check-core.ts +242 -0
- package/src/data/data-ref.ts +145 -0
- package/src/data/vite-plugin-data.ts +290 -0
- package/src/index.ts +48 -0
- package/src/input/input-manager.ts +1206 -32
- package/src/input/input-types.ts +155 -3
- package/src/input/prompt-labels.ts +122 -0
- package/src/input/rebind-controller.ts +105 -0
- package/src/input/schema.ts +206 -52
- package/src/react/use-data.ts +114 -0
- package/src/react/use-selection.tsx +135 -0
- package/src/runtime/create-runtime.ts +30 -9
- package/src/runtime/render-audio-control.ts +168 -0
- package/src/runtime/render-control.ts +522 -0
- package/src/runtime/render-seed.ts +79 -0
- package/src/runtime/types.ts +0 -5
- package/src/scene/asset-loaders.ts +10 -36
- package/src/scene/asset-paths.ts +0 -2
- package/src/scene/asset-ref-check.ts +248 -0
- package/src/scene/parse.ts +133 -0
- package/src/scene/scene-loader.ts +81 -96
- package/src/scene/schema/animation.ts +30 -79
- package/src/scene/schema/entity.ts +20 -0
- package/src/scene/schema/index.ts +2 -12
- package/src/scene/user-data.ts +8 -9
- package/src/setup/setup-renderer.ts +9 -2
- package/src/tools/define-tool.ts +152 -0
- package/src/animation/anim-graph.ts +0 -406
- package/src/animation/anim-system.ts +0 -28
- package/src/animation/property-track.ts +0 -178
- package/src/animation/schema.ts +0 -204
- package/src/audio/ambient.ts +0 -300
- package/src/audio/impacts.ts +0 -212
- package/src/audio/movement.ts +0 -140
- package/src/audio/musical.ts +0 -200
- package/src/audio/ui-sounds.ts +0 -171
- package/src/audio/vehicle.ts +0 -235
- package/src/audio/weapons.ts +0 -152
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import type { SystemPhaseName } from '../core/types';
|
|
2
|
+
import type {
|
|
3
|
+
AnimationClock,
|
|
4
|
+
ClockCrossing,
|
|
5
|
+
ClockEvaluatorHandle,
|
|
6
|
+
ClockInterval,
|
|
7
|
+
} from './animation-clock';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* D5 — Cinematic Cues (spec §10 D5, §5.4, §3.2).
|
|
11
|
+
*
|
|
12
|
+
* `CinematicCue` is the deliberately small VGAI semantic for "gameplay
|
|
13
|
+
* consequences of cinematic time" (spec §3.2: "Theatre carries
|
|
14
|
+
* visual/directorial values; ordinary TypeScript cues carry gameplay
|
|
15
|
+
* consequences"). Cues live ALONGSIDE Theatre (`theatre-clock-binding.ts`,
|
|
16
|
+
* D2) — both are driven by the same canonical `AnimationClock`, but a cue
|
|
17
|
+
* is ordinary TypeScript with a `run`/`reverse` function, never a second
|
|
18
|
+
* property-animation format and never serialized executable code into
|
|
19
|
+
* Theatre state (spec §5.4).
|
|
20
|
+
*
|
|
21
|
+
* ## Fire-once, built on the clock's half-open interval convention
|
|
22
|
+
*
|
|
23
|
+
* The clock documents (see `ClockInterval` in `animation-clock.ts`) that a
|
|
24
|
+
* time `t` is CROSSED by a forward interval iff `t > from && t <= to`, and
|
|
25
|
+
* by a reverse interval iff `t < from && t >= to`. This module uses exactly
|
|
26
|
+
* that test (`crossesForward`/`crossesReverse` below) and nothing else to
|
|
27
|
+
* decide "did this crossing sweep past cue.time" — never a naive comparison
|
|
28
|
+
* of `previousTime`/`currentTime`, which is ambiguous across a loop wrap
|
|
29
|
+
* (one `ClockCrossing` can carry 2+ intervals, one per lap segment; see the
|
|
30
|
+
* clock's loop-wrap tests). Because a repeated `seek()` to the same time
|
|
31
|
+
* re-asserts a ZERO-LENGTH interval (`from === to`), and the half-open test
|
|
32
|
+
* never matches a zero-length interval, a cue naturally does not re-fire on
|
|
33
|
+
* a repeated seek to the same `t` with no extra bookkeeping required.
|
|
34
|
+
*
|
|
35
|
+
* ## Sticky fire-once state + explicit re-arm ("resetsOnLoop"/"restart")
|
|
36
|
+
*
|
|
37
|
+
* Beyond that per-crossing test, each cue additionally tracks whether it
|
|
38
|
+
* has EVER fired forward/reverse ("sticky" state, `CueState` below). Once
|
|
39
|
+
* fired, a cue does not fire again from ordinary play/seek traffic — this
|
|
40
|
+
* is what makes a one-shot story beat like `spawn-enemy` safe to scrub
|
|
41
|
+
* across repeatedly in an editor without re-triggering. Two things
|
|
42
|
+
* explicitly re-arm (clear) that sticky state:
|
|
43
|
+
*
|
|
44
|
+
* - a loop-wrapping crossing (`crossing.looped === true`, which — per the
|
|
45
|
+
* clock's own contract — only `advance()` can ever produce; `seek()`
|
|
46
|
+
* always reports `looped: false`) re-arms only cues with
|
|
47
|
+
* `resetsOnLoop: true`, once per lap boundary actually swept (so a
|
|
48
|
+
* single giant multi-lap `advance()` correctly re-fires a per-lap cue
|
|
49
|
+
* once per lap, not just once for the whole call);
|
|
50
|
+
* - `CueRunner.reset()` unconditionally re-arms EVERY cue — this is the
|
|
51
|
+
* "restart" policy: the intended call when a cinematic explicitly
|
|
52
|
+
* restarts from the top and cues should be able to replay.
|
|
53
|
+
*
|
|
54
|
+
* ## Seek vs. play ("firesDuringSeek")
|
|
55
|
+
*
|
|
56
|
+
* `AnimationClock.seek()` and `AnimationClock.advance()` both funnel
|
|
57
|
+
* through the same `ClockCrossing` shape — the clock does not itself tag a
|
|
58
|
+
* crossing with which method produced it (that distinction is deliberately
|
|
59
|
+
* NOT added to the D1 clock; see the D1 follow-up note in
|
|
60
|
+
* `animation-clock.ts`, which stays scoped to the epsilon-clamp fix only).
|
|
61
|
+
* This module makes the distinction its own responsibility: drive the clock
|
|
62
|
+
* through `CueRunner.seek(t)` / `CueRunner.advance(dt)` (not
|
|
63
|
+
* `clock.seek`/`clock.advance` directly) and the runner tags the resulting
|
|
64
|
+
* crossing with its true source before evaluating cues. A cue with
|
|
65
|
+
* `firesDuringSeek` unset/false is skipped entirely (both directions, and
|
|
66
|
+
* the auto-cleanup/compensation described below) on a seek-sourced
|
|
67
|
+
* crossing — this is what keeps authoring-time scrubbing from spamming
|
|
68
|
+
* `player.lockInput()`/`enemies.spawn()` side effects, matching the spirit
|
|
69
|
+
* of the D4 director AC ("seeking ... without spuriously firing gameplay
|
|
70
|
+
* cues"). Driving the clock directly (bypassing the runner's wrapper
|
|
71
|
+
* methods) is still safe — the crossing is simply treated as `'advance'`
|
|
72
|
+
* sourced by default — but loses seek-vs-play discrimination; this is a
|
|
73
|
+
* documented, deliberate limitation, not a bug.
|
|
74
|
+
*
|
|
75
|
+
* ## Equal-timestamp tiebreak
|
|
76
|
+
*
|
|
77
|
+
* Cues are evaluated in ascending `time` order; cues with an EQUAL `time`
|
|
78
|
+
* are evaluated in REGISTRATION order (the order they appear in the array
|
|
79
|
+
* passed to `createCueRunner`) — the same tiebreak convention
|
|
80
|
+
* `AnimationClock.subscribe` itself uses for same-phase evaluators
|
|
81
|
+
* (`animation-clock.ts`'s `EvaluatorEntry.order`).
|
|
82
|
+
*
|
|
83
|
+
* ## Cleanup / compensation
|
|
84
|
+
*
|
|
85
|
+
* `run`/`reverse` may return a `CueCleanup` function. It is invoked (and
|
|
86
|
+
* then discarded) at whichever of these happens first:
|
|
87
|
+
*
|
|
88
|
+
* - a reverse-direction crossing of the SAME cue (even if the cue has no
|
|
89
|
+
* explicit `reverse` handler — this is the "compensation" half of the
|
|
90
|
+
* contract: undo whatever `run` set up, symmetrically, when time moves
|
|
91
|
+
* back past it), subject to the same `firesDuringSeek` gating as any
|
|
92
|
+
* other reverse-direction reaction;
|
|
93
|
+
* - the cue being re-armed by a loop wrap (`resetsOnLoop`) or by
|
|
94
|
+
* `reset()` — any not-yet-compensated effect is cleaned up before the
|
|
95
|
+
* cue is made eligible to fire again;
|
|
96
|
+
* - `CueRunner.dispose()` — final teardown.
|
|
97
|
+
*
|
|
98
|
+
* `run`'s cleanup and `reverse`'s cleanup are tracked independently, so an
|
|
99
|
+
* explicit `reverse` handler that ALSO returns a cleanup gets its own
|
|
100
|
+
* compensation slot (invoked on re-arm/dispose, since there is no
|
|
101
|
+
* "un-reverse" direction to compensate it from).
|
|
102
|
+
*
|
|
103
|
+
* ## Error isolation
|
|
104
|
+
*
|
|
105
|
+
* Every `run`/`reverse`/cleanup invocation is individually try/caught. A
|
|
106
|
+
* throw is recorded as a `CueError` (`cueId` + `time` + which `phase`
|
|
107
|
+
* threw) via `getErrors()`/the optional `onError` callback, and NEVER
|
|
108
|
+
* re-thrown — one failing cue can neither block a sibling cue in the same
|
|
109
|
+
* crossing nor corrupt the clock (the clock has already committed its new
|
|
110
|
+
* position before any cue runs; a cue is a pure reaction to a completed
|
|
111
|
+
* crossing, never a participant in producing one).
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
/** Optional compensation/cleanup a cue handler may return. */
|
|
115
|
+
export type CueCleanup = () => void;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* `void` (not `undefined`) is required here so an ordinary handler written
|
|
119
|
+
* as `run: (ctx) => { ctx.player.lockInput(); }` (no explicit `return`,
|
|
120
|
+
* which TS types as `void`) stays assignable — TS's special-cased "a
|
|
121
|
+
* `void`-typed callback return position accepts any return value"
|
|
122
|
+
* assignability rule does NOT apply to `undefined`; swapping this to
|
|
123
|
+
* `undefined | CueCleanup` breaks every cue author whose handler doesn't
|
|
124
|
+
* end in a bare `return;`.
|
|
125
|
+
*/
|
|
126
|
+
// biome-ignore lint/suspicious/noConfusingVoidType: see doc comment above — void is required for callback assignability, not a mistake.
|
|
127
|
+
export type CueHandlerResult = void | CueCleanup;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* A single cinematic cue: a stable id, a time in seconds, and the gameplay
|
|
131
|
+
* reaction(s) to crossing that time. See the module doc above and spec
|
|
132
|
+
* §5.4 for the full contract.
|
|
133
|
+
*/
|
|
134
|
+
export interface CinematicCue<TContext = unknown> {
|
|
135
|
+
/** Stable identifier, unique within one `CueRunner`. */
|
|
136
|
+
readonly id: string;
|
|
137
|
+
/** Time in seconds, in the same domain as the driving `AnimationClock`. */
|
|
138
|
+
readonly time: number;
|
|
139
|
+
/** Forward-crossing behavior. May return a cleanup/compensation function. */
|
|
140
|
+
run(ctx: TContext): CueHandlerResult;
|
|
141
|
+
/** Optional reverse (backward-crossing) behavior. May return its own cleanup. */
|
|
142
|
+
reverse?(ctx: TContext): CueHandlerResult;
|
|
143
|
+
/**
|
|
144
|
+
* Whether this cue reacts to a `CueRunner.seek()`-sourced crossing (in
|
|
145
|
+
* either direction). Default `false` — explicit seeks (authoring-time
|
|
146
|
+
* scrubbing, skip/jump) do not fire gameplay-consequential cues unless a
|
|
147
|
+
* cue opts in.
|
|
148
|
+
*/
|
|
149
|
+
readonly firesDuringSeek?: boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Whether a loop-wrapping crossing re-arms this cue so it can fire again
|
|
152
|
+
* next lap. Default `false` — the cue fires (at most) once for the
|
|
153
|
+
* lifetime of the runner, until an explicit `reset()`.
|
|
154
|
+
*/
|
|
155
|
+
readonly resetsOnLoop?: boolean;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export type CueErrorPhase = 'run' | 'reverse' | 'cleanup';
|
|
159
|
+
|
|
160
|
+
/** A failed cue's identity + which phase threw, never a live Error re-throw. */
|
|
161
|
+
export interface CueError {
|
|
162
|
+
readonly cueId: string;
|
|
163
|
+
readonly time: number;
|
|
164
|
+
readonly phase: CueErrorPhase;
|
|
165
|
+
readonly error: unknown;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Which `AnimationClock` method produced the crossing being evaluated. */
|
|
169
|
+
export type CueCrossingSource = 'advance' | 'seek';
|
|
170
|
+
|
|
171
|
+
export interface CueRunnerOptions<TContext> {
|
|
172
|
+
/** The game context passed to every `run`/`reverse` call. */
|
|
173
|
+
context: TContext;
|
|
174
|
+
/**
|
|
175
|
+
* Which `AnimationClock` phase to evaluate cues in. Default `'gameLogic'`
|
|
176
|
+
* — gameplay consequences run before the `'animation'` phase Theatre
|
|
177
|
+
* bindings use (`theatre-clock-binding.ts`), matching `PHASE_ORDER`.
|
|
178
|
+
*/
|
|
179
|
+
phase?: SystemPhaseName;
|
|
180
|
+
/** Called synchronously whenever a cue's run/reverse/cleanup throws. */
|
|
181
|
+
onError?: (err: CueError) => void;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The runner's public surface is intentionally context-agnostic (`TContext`
|
|
186
|
+
* only shapes construction — the cue handlers it drives — not this object's
|
|
187
|
+
* own methods), so it takes no type parameter.
|
|
188
|
+
*/
|
|
189
|
+
export interface CueRunner {
|
|
190
|
+
/**
|
|
191
|
+
* Explicit seek, tagged as `'seek'`-sourced for `firesDuringSeek` gating.
|
|
192
|
+
* Prefer this over calling the underlying clock's `seek()` directly.
|
|
193
|
+
*/
|
|
194
|
+
seek(t: number): ClockCrossing;
|
|
195
|
+
/**
|
|
196
|
+
* Playback tick, tagged as `'advance'`-sourced. Prefer this over calling
|
|
197
|
+
* the underlying clock's `advance()` directly. No-op (returns `null`)
|
|
198
|
+
* under the same conditions `AnimationClock.advance` is a no-op.
|
|
199
|
+
*/
|
|
200
|
+
advance(dt: number): ClockCrossing | null;
|
|
201
|
+
/** Re-arms every cue (the "restart" policy) and runs any pending cleanups. */
|
|
202
|
+
reset(): void;
|
|
203
|
+
/** Every cue failure recorded so far, in the order they occurred. */
|
|
204
|
+
getErrors(): readonly CueError[];
|
|
205
|
+
/** Clears the recorded error log (does not affect cue armed state). */
|
|
206
|
+
clearErrors(): void;
|
|
207
|
+
/** Unsubscribes from the clock and runs any pending cleanups. */
|
|
208
|
+
dispose(): void;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface CueState {
|
|
212
|
+
firedForward: boolean;
|
|
213
|
+
firedReverse: boolean;
|
|
214
|
+
forwardCleanup: CueCleanup | undefined;
|
|
215
|
+
reverseCleanup: CueCleanup | undefined;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
interface OrderedCue<TContext> {
|
|
219
|
+
cue: CinematicCue<TContext>;
|
|
220
|
+
registrationOrder: number;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function crossesForward(interval: ClockInterval, cueTime: number): boolean {
|
|
224
|
+
return interval.direction === 'forward' && cueTime > interval.from && cueTime <= interval.to;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function crossesReverse(interval: ClockInterval, cueTime: number): boolean {
|
|
228
|
+
return interval.direction === 'reverse' && cueTime < interval.from && cueTime >= interval.to;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Build a cue runner bound to `clock`, evaluating `cues` on every crossing.
|
|
233
|
+
* See the module doc comment for the full policy contract.
|
|
234
|
+
*/
|
|
235
|
+
export function createCueRunner<TContext>(
|
|
236
|
+
clock: AnimationClock,
|
|
237
|
+
cues: readonly CinematicCue<TContext>[],
|
|
238
|
+
options: CueRunnerOptions<TContext>,
|
|
239
|
+
): CueRunner {
|
|
240
|
+
const seen = new Set<string>();
|
|
241
|
+
for (const cue of cues) {
|
|
242
|
+
if (seen.has(cue.id)) {
|
|
243
|
+
throw new Error(`[CueRunner] duplicate cue id "${cue.id}" — ids must be unique`);
|
|
244
|
+
}
|
|
245
|
+
seen.add(cue.id);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const ordered: OrderedCue<TContext>[] = cues.map((cue, registrationOrder) => ({
|
|
249
|
+
cue,
|
|
250
|
+
registrationOrder,
|
|
251
|
+
}));
|
|
252
|
+
ordered.sort((a, b) => {
|
|
253
|
+
if (a.cue.time !== b.cue.time) return a.cue.time - b.cue.time;
|
|
254
|
+
return a.registrationOrder - b.registrationOrder;
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
const context = options.context;
|
|
258
|
+
const phase = options.phase ?? 'gameLogic';
|
|
259
|
+
const errors: CueError[] = [];
|
|
260
|
+
const states = new Map<string, CueState>();
|
|
261
|
+
for (const { cue } of ordered) {
|
|
262
|
+
states.set(cue.id, {
|
|
263
|
+
firedForward: false,
|
|
264
|
+
firedReverse: false,
|
|
265
|
+
forwardCleanup: undefined,
|
|
266
|
+
reverseCleanup: undefined,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function stateOf(id: string): CueState {
|
|
271
|
+
const state = states.get(id);
|
|
272
|
+
if (!state) throw new Error(`[CueRunner] unknown cue id "${id}"`); // unreachable — defensive
|
|
273
|
+
return state;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function reportError(cueId: string, time: number, errPhase: CueErrorPhase, error: unknown): void {
|
|
277
|
+
const cueError: CueError = { cueId, time, phase: errPhase, error };
|
|
278
|
+
errors.push(cueError);
|
|
279
|
+
options.onError?.(cueError);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function invokeHandler(
|
|
283
|
+
cue: CinematicCue<TContext>,
|
|
284
|
+
errPhase: 'run' | 'reverse',
|
|
285
|
+
handler: (ctx: TContext) => CueHandlerResult,
|
|
286
|
+
): CueCleanup | undefined {
|
|
287
|
+
try {
|
|
288
|
+
const result = handler(context);
|
|
289
|
+
return typeof result === 'function' ? result : undefined;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
reportError(cue.id, cue.time, errPhase, error);
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function invokeCleanup(cue: CinematicCue<TContext>, cleanup: CueCleanup): void {
|
|
297
|
+
try {
|
|
298
|
+
cleanup();
|
|
299
|
+
} catch (error) {
|
|
300
|
+
reportError(cue.id, cue.time, 'cleanup', error);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// NOTE: no crossing-scoped "already fired this crossing" guard beyond the
|
|
305
|
+
// per-cue `state.firedForward`/`state.firedReverse` flags below — those
|
|
306
|
+
// flags are sufficient (each cue is visited at most once per interval,
|
|
307
|
+
// and a fire sets the flag before the next interval is scanned) AND, in
|
|
308
|
+
// the resetsOnLoop case, `rearmLoopCues` deliberately clears them mid
|
|
309
|
+
// crossing so a cue CAN legitimately fire again in a later interval of
|
|
310
|
+
// the same multi-lap crossing (once per lap boundary actually crossed).
|
|
311
|
+
// A crossing-wide "fired once ever" set would silently defeat that.
|
|
312
|
+
function processForwardInterval(interval: ClockInterval, source: CueCrossingSource): void {
|
|
313
|
+
for (const { cue } of ordered) {
|
|
314
|
+
const state = stateOf(cue.id);
|
|
315
|
+
if (state.firedForward) continue;
|
|
316
|
+
if (!crossesForward(interval, cue.time)) continue;
|
|
317
|
+
if (source === 'seek' && !cue.firesDuringSeek) continue;
|
|
318
|
+
|
|
319
|
+
state.firedForward = true;
|
|
320
|
+
const cleanup = invokeHandler(cue, 'run', cue.run);
|
|
321
|
+
if (cleanup) state.forwardCleanup = cleanup;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Split out of processReverseInterval to keep both functions under the
|
|
326
|
+
// project's cognitive-complexity budget: this is the "what happens to ONE
|
|
327
|
+
// cue on a reverse crossing" reaction — the explicit reverse() handler
|
|
328
|
+
// (if any, fire-once) plus the automatic forward-cleanup compensation
|
|
329
|
+
// (independent of whether reverse() exists) — see the module doc's
|
|
330
|
+
// "Cleanup / compensation" section.
|
|
331
|
+
function reactToReverseCrossing(cue: CinematicCue<TContext>, state: CueState): void {
|
|
332
|
+
if (cue.reverse && !state.firedReverse) {
|
|
333
|
+
state.firedReverse = true;
|
|
334
|
+
const cleanup = invokeHandler(cue, 'reverse', cue.reverse);
|
|
335
|
+
if (cleanup) state.reverseCleanup = cleanup;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (state.forwardCleanup) {
|
|
339
|
+
const cleanup = state.forwardCleanup;
|
|
340
|
+
state.forwardCleanup = undefined;
|
|
341
|
+
invokeCleanup(cue, cleanup);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function processReverseInterval(interval: ClockInterval, source: CueCrossingSource): void {
|
|
346
|
+
for (const { cue } of ordered) {
|
|
347
|
+
if (!crossesReverse(interval, cue.time)) continue;
|
|
348
|
+
if (source === 'seek' && !cue.firesDuringSeek) continue;
|
|
349
|
+
reactToReverseCrossing(cue, stateOf(cue.id));
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function rearmLoopCues(): void {
|
|
354
|
+
for (const { cue } of ordered) {
|
|
355
|
+
if (!cue.resetsOnLoop) continue;
|
|
356
|
+
const state = stateOf(cue.id);
|
|
357
|
+
if (!state.firedForward && !state.firedReverse) continue; // nothing to rearm
|
|
358
|
+
if (state.forwardCleanup) {
|
|
359
|
+
invokeCleanup(cue, state.forwardCleanup);
|
|
360
|
+
state.forwardCleanup = undefined;
|
|
361
|
+
}
|
|
362
|
+
if (state.reverseCleanup) {
|
|
363
|
+
invokeCleanup(cue, state.reverseCleanup);
|
|
364
|
+
state.reverseCleanup = undefined;
|
|
365
|
+
}
|
|
366
|
+
state.firedForward = false;
|
|
367
|
+
state.firedReverse = false;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function handleCrossing(crossing: ClockCrossing, source: CueCrossingSource): void {
|
|
372
|
+
for (const interval of crossing.intervals) {
|
|
373
|
+
if (interval.direction === 'forward') {
|
|
374
|
+
processForwardInterval(interval, source);
|
|
375
|
+
} else {
|
|
376
|
+
processReverseInterval(interval, source);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (crossing.looped) {
|
|
380
|
+
const completesLap =
|
|
381
|
+
(interval.direction === 'forward' && interval.to === clock.range.end) ||
|
|
382
|
+
(interval.direction === 'reverse' && interval.to === clock.range.start);
|
|
383
|
+
if (completesLap) rearmLoopCues();
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
let pendingSource: CueCrossingSource = 'advance';
|
|
389
|
+
const handle: ClockEvaluatorHandle = clock.subscribe(phase, (crossing) => {
|
|
390
|
+
handleCrossing(crossing, pendingSource);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
let disposed = false;
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
seek(t: number): ClockCrossing {
|
|
397
|
+
pendingSource = 'seek';
|
|
398
|
+
try {
|
|
399
|
+
return clock.seek(t);
|
|
400
|
+
} finally {
|
|
401
|
+
pendingSource = 'advance';
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
|
|
405
|
+
advance(dt: number): ClockCrossing | null {
|
|
406
|
+
pendingSource = 'advance';
|
|
407
|
+
return clock.advance(dt);
|
|
408
|
+
},
|
|
409
|
+
|
|
410
|
+
reset(): void {
|
|
411
|
+
for (const { cue } of ordered) {
|
|
412
|
+
const state = stateOf(cue.id);
|
|
413
|
+
if (state.forwardCleanup) {
|
|
414
|
+
invokeCleanup(cue, state.forwardCleanup);
|
|
415
|
+
state.forwardCleanup = undefined;
|
|
416
|
+
}
|
|
417
|
+
if (state.reverseCleanup) {
|
|
418
|
+
invokeCleanup(cue, state.reverseCleanup);
|
|
419
|
+
state.reverseCleanup = undefined;
|
|
420
|
+
}
|
|
421
|
+
state.firedForward = false;
|
|
422
|
+
state.firedReverse = false;
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
|
|
426
|
+
getErrors(): readonly CueError[] {
|
|
427
|
+
return errors;
|
|
428
|
+
},
|
|
429
|
+
|
|
430
|
+
clearErrors(): void {
|
|
431
|
+
errors.length = 0;
|
|
432
|
+
},
|
|
433
|
+
|
|
434
|
+
dispose(): void {
|
|
435
|
+
if (disposed) return;
|
|
436
|
+
disposed = true;
|
|
437
|
+
handle.dispose();
|
|
438
|
+
for (const { cue } of ordered) {
|
|
439
|
+
const state = stateOf(cue.id);
|
|
440
|
+
if (state.forwardCleanup) {
|
|
441
|
+
invokeCleanup(cue, state.forwardCleanup);
|
|
442
|
+
state.forwardCleanup = undefined;
|
|
443
|
+
}
|
|
444
|
+
if (state.reverseCleanup) {
|
|
445
|
+
invokeCleanup(cue, state.reverseCleanup);
|
|
446
|
+
state.reverseCleanup = undefined;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
};
|
|
451
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
/** Common aliases used by many free humanoid packs. Scene-authored aliases override these. */
|
|
4
|
+
const DEFAULT_CLIP_ALIASES: Record<string, string> = {
|
|
5
|
+
walking: 'walk',
|
|
6
|
+
running: 'run',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Build the clip lookup shared by runtime and editor.
|
|
11
|
+
*
|
|
12
|
+
* GLTF exporters disagree about case and may prefix animation names with an
|
|
13
|
+
* armature (`Armature|Idle`). Keep the exact exported suffix while also
|
|
14
|
+
* exposing a lowercase lookup, then apply aliases case-insensitively. This
|
|
15
|
+
* lets authored graphs use either `Idle_Loop` or `idle_loop` without silently
|
|
16
|
+
* falling back to the bind pose.
|
|
17
|
+
*/
|
|
18
|
+
export function buildClipMap(
|
|
19
|
+
animations: THREE.AnimationClip[],
|
|
20
|
+
aliases: Record<string, string> = {},
|
|
21
|
+
): Map<string, THREE.AnimationClip> {
|
|
22
|
+
const clips = new Map<string, THREE.AnimationClip>();
|
|
23
|
+
const canonical = new Map<string, THREE.AnimationClip>();
|
|
24
|
+
|
|
25
|
+
for (const clip of animations) {
|
|
26
|
+
const raw = clip.name.split('|').pop()?.trim() || clip.name;
|
|
27
|
+
canonical.set(raw.toLowerCase(), clip);
|
|
28
|
+
if (!clips.has(raw)) clips.set(raw, clip);
|
|
29
|
+
if (!clips.has(raw.toLowerCase())) clips.set(raw.toLowerCase(), clip);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const mergedAliases = { ...DEFAULT_CLIP_ALIASES, ...aliases };
|
|
33
|
+
for (const [source, alias] of Object.entries(mergedAliases)) {
|
|
34
|
+
const clip = canonical.get(source.toLowerCase());
|
|
35
|
+
if (!clip) continue;
|
|
36
|
+
if (!clips.has(alias)) clips.set(alias, clip);
|
|
37
|
+
if (!clips.has(alias.toLowerCase())) clips.set(alias.toLowerCase(), clip);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return clips;
|
|
41
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import gsap from 'gsap';
|
|
2
|
+
import type { SystemPhaseName } from '../core/types';
|
|
3
|
+
import type { AnimationClock, ClockEvaluatorHandle } from './animation-clock';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* D7 — register a native, paused GSAP timeline on the canonical
|
|
7
|
+
* `AnimationClock` (spec §10 D7, §5.5 GSAP Contract, §3.2).
|
|
8
|
+
*
|
|
9
|
+
* Mirrors `theatre-clock-binding.ts` (D2)'s shape: VGAI's entire GSAP
|
|
10
|
+
* integration is "who drives time". Games build GSAP timelines with GSAP's
|
|
11
|
+
* own native, un-renamed API (`gsap.timeline()`, `.to()`, `.from()`, …,
|
|
12
|
+
* spec §5.5) — this module never wraps or renames the tween-building API. It
|
|
13
|
+
* only stores the native `gsap.core.Timeline` and seeks it every time the
|
|
14
|
+
* clock moves, exactly like the Theatre sequence binding seeks
|
|
15
|
+
* `sequence.position`.
|
|
16
|
+
*
|
|
17
|
+
* ## Unregistered GSAP is unaffected (§5.5 contract)
|
|
18
|
+
*
|
|
19
|
+
* `gsap.to(enemy.position, { … })` called anywhere in game code — without
|
|
20
|
+
* ever touching this module — keeps running on GSAP's own real-time,
|
|
21
|
+
* `requestAnimationFrame`-driven global ticker exactly as GSAP ships it. This
|
|
22
|
+
* module does not touch `gsap.ticker`, `gsap.globalTimeline`, or any other
|
|
23
|
+
* global GSAP state, precisely so it cannot perturb that ordinary real-time
|
|
24
|
+
* code path. Only a timeline explicitly passed to `registerGsap` — and
|
|
25
|
+
* created paused — participates in deterministic scrub/export.
|
|
26
|
+
*
|
|
27
|
+
* ## Why a PAUSED timeline seeked with `.time()` is deterministic
|
|
28
|
+
*
|
|
29
|
+
* GSAP's global ticker only auto-advances animations that are actually
|
|
30
|
+
* playing; a timeline created with `{ paused: true }` (and never resumed) is
|
|
31
|
+
* never touched by the ticker's rAF-driven `dt` accumulation, so wall-clock
|
|
32
|
+
* elapsed time, dropped frames, and GSAP's lag-smoothing heuristics (which
|
|
33
|
+
* exist purely to compensate a *playing* animation for an irregular ticker
|
|
34
|
+
* `dt`) cannot affect it. The only thing that ever moves a registered
|
|
35
|
+
* timeline's playhead is this module's own `timeline.time(clock.time)` call,
|
|
36
|
+
* driven synchronously off the clock — same story as `theatre-clock-binding`
|
|
37
|
+
* driving `sequence.position` off the clock instead of Theatre's own raf
|
|
38
|
+
* loop. This is proven directly against the real `gsap` runtime in
|
|
39
|
+
* `packages/engine/test/gsap-registration.test.ts` (including a real
|
|
40
|
+
* wall-clock `setTimeout` wait between two `clock.seek()` calls to the same
|
|
41
|
+
* time, asserting the sampled value is bit-for-bit identical — nothing
|
|
42
|
+
* "polished" the value while real time passed). `timeline.time(value)` (not
|
|
43
|
+
* `.seek(value)`) is used because it takes only a numeric offset in the
|
|
44
|
+
* clock's own second-denominated domain — `.seek()`'s label-string overload
|
|
45
|
+
* is irrelevant here and would only widen the accepted input past what a
|
|
46
|
+
* clock time actually is. Neither call resumes playback; both simply
|
|
47
|
+
* position an already-paused timeline, which is why this module never calls
|
|
48
|
+
* `.play()`/`.resume()`.
|
|
49
|
+
*
|
|
50
|
+
* ## Phase choice
|
|
51
|
+
*
|
|
52
|
+
* Registered by default at the `'animation'` phase — the same phase
|
|
53
|
+
* `bindClockToTheatreSequence` (D2) uses, and the same phase
|
|
54
|
+
* XState-bound `AnimationMixer` playback ticks in (see `ARCHITECTURE.md`'s
|
|
55
|
+
* phase table). A registered GSAP timeline commonly targets the same
|
|
56
|
+
* Object3D/material properties a Theatre-driven object binding also writes,
|
|
57
|
+
* so keeping both in the `'animation'` phase (ahead of `'preRender'`, where
|
|
58
|
+
* camera/material reads happen) avoids ordering surprises.
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
export interface GsapRegistrationOptions {
|
|
62
|
+
/** Which `AnimationClock` phase to seek the timeline in. Defaults to `'animation'`. */
|
|
63
|
+
phase?: SystemPhaseName;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface GsapRegistration {
|
|
67
|
+
/**
|
|
68
|
+
* Removes the clock evaluator and stops driving the timeline (no further
|
|
69
|
+
* `timeline.time(...)` calls occur after this). Also frees this
|
|
70
|
+
* clock+timeline pair for re-registration (see `GsapRegistrationError`'s
|
|
71
|
+
* `'duplicate'` case below).
|
|
72
|
+
*/
|
|
73
|
+
dispose(): void;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Thrown by `registerGsap` when the input does not satisfy the D7 contract.
|
|
78
|
+
* `code` distinguishes the three rejection reasons so a caller can branch on
|
|
79
|
+
* it programmatically instead of string-matching `message`:
|
|
80
|
+
*
|
|
81
|
+
* - `'not-a-timeline'` — the second argument is not a real
|
|
82
|
+
* `gsap.core.Timeline` instance (e.g. a plain object, a single GSAP
|
|
83
|
+
* `Tween`, or `undefined`). Checked with `instanceof gsap.core.Timeline`
|
|
84
|
+
* against the actual installed GSAP runtime, not duck-typing, so a
|
|
85
|
+
* same-shaped fake cannot slip through.
|
|
86
|
+
* - `'not-paused'` — the timeline exists but was not created with
|
|
87
|
+
* `{ paused: true }` (or was later resumed) at registration time. This
|
|
88
|
+
* module deliberately REJECTS rather than silently force-pausing: a
|
|
89
|
+
* caller who already relies on the timeline advancing in real time (e.g.
|
|
90
|
+
* a UI polish tween that happens to also get registered by mistake) would
|
|
91
|
+
* otherwise have its behavior silently changed. Rejecting makes the fix
|
|
92
|
+
* (`gsap.timeline({ paused: true })`) obvious at the call site instead of
|
|
93
|
+
* producing a hard-to-notice runtime pause.
|
|
94
|
+
* - `'duplicate'` — this exact timeline is already registered against this
|
|
95
|
+
* exact clock. Detected per `(clock, timeline)` pair (not globally), so
|
|
96
|
+
* the same timeline may legitimately be registered against two
|
|
97
|
+
* independent clocks/cinematic contexts — mirroring D2's "multiple
|
|
98
|
+
* projects/sheets coexist" allowance — while registering it twice on the
|
|
99
|
+
* SAME clock (almost always a bug: a duplicate `useEffect` run, a missed
|
|
100
|
+
* disposer, …) is caught immediately instead of silently doubling the
|
|
101
|
+
* number of `.time()` writes per crossing.
|
|
102
|
+
*/
|
|
103
|
+
export class GsapRegistrationError extends Error {
|
|
104
|
+
constructor(
|
|
105
|
+
message: string,
|
|
106
|
+
readonly code: 'not-a-timeline' | 'not-paused' | 'duplicate',
|
|
107
|
+
) {
|
|
108
|
+
super(message);
|
|
109
|
+
this.name = 'GsapRegistrationError';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Per-clock membership of already-registered timelines. A WeakMap keyed by
|
|
114
|
+
// clock (not a field on AnimationClock itself — D1 owns no knowledge of
|
|
115
|
+
// GSAP) holding a WeakSet keyed by timeline, so neither the clock nor a
|
|
116
|
+
// disposed/dropped timeline is kept alive by this module.
|
|
117
|
+
const registeredByClock = new WeakMap<AnimationClock, WeakSet<gsap.core.Timeline>>();
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Register a native, paused `gsap.core.Timeline` on `clock`: from now on,
|
|
121
|
+
* every clock crossing (`seek`, `advance`, idempotent re-seeks, `setRange`
|
|
122
|
+
* clamps — anything that fires a `ClockEvaluator`, per `animation-clock.ts`)
|
|
123
|
+
* positions the timeline at `clock.time` via `timeline.time(clock.time)`.
|
|
124
|
+
* The timeline is never played/resumed — it stays paused and is driven
|
|
125
|
+
* exclusively by the clock, both in live preview and in offline
|
|
126
|
+
* frame-by-frame export (whatever calls `clock.seek`/`clock.seekFrame`).
|
|
127
|
+
*
|
|
128
|
+
* Throws `GsapRegistrationError` if `timeline` is not a real
|
|
129
|
+
* `gsap.core.Timeline`, is not paused, or is already registered against this
|
|
130
|
+
* `clock` — see that class's doc comment for the exact policy on each case.
|
|
131
|
+
*
|
|
132
|
+
* Returns a `GsapRegistration` whose `dispose()` removes the clock evaluator
|
|
133
|
+
* (mirrors `bindClockToTheatreSequence`'s `TheatreClockBinding`).
|
|
134
|
+
*/
|
|
135
|
+
export function registerGsap(
|
|
136
|
+
clock: AnimationClock,
|
|
137
|
+
timeline: gsap.core.Timeline,
|
|
138
|
+
options: GsapRegistrationOptions = {},
|
|
139
|
+
): GsapRegistration {
|
|
140
|
+
if (!(timeline instanceof gsap.core.Timeline)) {
|
|
141
|
+
throw new GsapRegistrationError(
|
|
142
|
+
'[registerGsap] expected a native gsap.core.Timeline (e.g. gsap.timeline({ paused: true })), ' +
|
|
143
|
+
`got ${timeline === null ? 'null' : typeof timeline}`,
|
|
144
|
+
'not-a-timeline',
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (!timeline.paused()) {
|
|
148
|
+
throw new GsapRegistrationError(
|
|
149
|
+
'[registerGsap] timeline must be created paused — gsap.timeline({ paused: true }) — before ' +
|
|
150
|
+
'registration; a registered timeline is driven exclusively by the clock and must never also ' +
|
|
151
|
+
'be advancing under its own real-time playback',
|
|
152
|
+
'not-paused',
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let seenForClock = registeredByClock.get(clock);
|
|
157
|
+
if (!seenForClock) {
|
|
158
|
+
seenForClock = new WeakSet();
|
|
159
|
+
registeredByClock.set(clock, seenForClock);
|
|
160
|
+
}
|
|
161
|
+
if (seenForClock.has(timeline)) {
|
|
162
|
+
throw new GsapRegistrationError(
|
|
163
|
+
'[registerGsap] this timeline is already registered against this clock — dispose() the prior ' +
|
|
164
|
+
'registration before registering it again',
|
|
165
|
+
'duplicate',
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
seenForClock.add(timeline);
|
|
169
|
+
|
|
170
|
+
const phase = options.phase ?? 'animation';
|
|
171
|
+
const handle: ClockEvaluatorHandle = clock.subscribe(phase, () => {
|
|
172
|
+
timeline.time(clock.time);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
let disposed = false;
|
|
176
|
+
return {
|
|
177
|
+
dispose(): void {
|
|
178
|
+
if (disposed) return;
|
|
179
|
+
disposed = true;
|
|
180
|
+
handle.dispose();
|
|
181
|
+
seenForClock!.delete(timeline);
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|