@number10/jsx-core 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +667 -0
- package/README.md +38 -0
- package/dist/animation/animated-signal.cjs +19 -0
- package/dist/animation/animated-signal.cjs.map +1 -0
- package/dist/animation/animated-signal.d.ts +35 -0
- package/dist/animation/animated-signal.d.ts.map +1 -0
- package/dist/animation/animated-signal.js +19 -0
- package/dist/animation/animated-signal.js.map +1 -0
- package/dist/animation/create-spring.cjs +80 -0
- package/dist/animation/create-spring.cjs.map +1 -0
- package/dist/animation/create-spring.d.ts +56 -0
- package/dist/animation/create-spring.d.ts.map +1 -0
- package/dist/animation/create-spring.js +80 -0
- package/dist/animation/create-spring.js.map +1 -0
- package/dist/animation/easing.cjs +76 -0
- package/dist/animation/easing.cjs.map +1 -0
- package/dist/animation/easing.d.ts +45 -0
- package/dist/animation/easing.d.ts.map +1 -0
- package/dist/animation/easing.js +76 -0
- package/dist/animation/easing.js.map +1 -0
- package/dist/animation/effect-definitions.cjs +441 -0
- package/dist/animation/effect-definitions.cjs.map +1 -0
- package/dist/animation/effect-definitions.d.ts +60 -0
- package/dist/animation/effect-definitions.d.ts.map +1 -0
- package/dist/animation/effect-definitions.js +441 -0
- package/dist/animation/effect-definitions.js.map +1 -0
- package/dist/animation/effect-engine.cjs +189 -0
- package/dist/animation/effect-engine.cjs.map +1 -0
- package/dist/animation/effect-engine.d.ts +70 -0
- package/dist/animation/effect-engine.d.ts.map +1 -0
- package/dist/animation/effect-engine.js +189 -0
- package/dist/animation/effect-engine.js.map +1 -0
- package/dist/animation/index.d.ts +24 -0
- package/dist/animation/index.d.ts.map +1 -0
- package/dist/animation/spring-physics.cjs +94 -0
- package/dist/animation/spring-physics.cjs.map +1 -0
- package/dist/animation/spring-physics.d.ts +145 -0
- package/dist/animation/spring-physics.d.ts.map +1 -0
- package/dist/animation/spring-physics.js +94 -0
- package/dist/animation/spring-physics.js.map +1 -0
- package/dist/animation/tween.cjs +67 -0
- package/dist/animation/tween.cjs.map +1 -0
- package/dist/animation/tween.d.ts +60 -0
- package/dist/animation/tween.d.ts.map +1 -0
- package/dist/animation/tween.js +67 -0
- package/dist/animation/tween.js.map +1 -0
- package/dist/animation/types.d.ts +31 -0
- package/dist/animation/types.d.ts.map +1 -0
- package/dist/animation/useSpring.cjs +152 -0
- package/dist/animation/useSpring.cjs.map +1 -0
- package/dist/animation/useSpring.d.ts +55 -0
- package/dist/animation/useSpring.d.ts.map +1 -0
- package/dist/animation/useSpring.js +149 -0
- package/dist/animation/useSpring.js.map +1 -0
- package/dist/animation/useTween.cjs +208 -0
- package/dist/animation/useTween.cjs.map +1 -0
- package/dist/animation/useTween.d.ts +116 -0
- package/dist/animation/useTween.d.ts.map +1 -0
- package/dist/animation/useTween.js +208 -0
- package/dist/animation/useTween.js.map +1 -0
- package/dist/border-geometry.cjs +447 -0
- package/dist/border-geometry.cjs.map +1 -0
- package/dist/border-geometry.d.ts +114 -0
- package/dist/border-geometry.d.ts.map +1 -0
- package/dist/border-geometry.js +447 -0
- package/dist/border-geometry.js.map +1 -0
- package/dist/colors/color-presets.cjs +236 -0
- package/dist/colors/color-presets.cjs.map +1 -0
- package/dist/colors/color-presets.d.ts +89 -0
- package/dist/colors/color-presets.d.ts.map +1 -0
- package/dist/colors/color-presets.js +236 -0
- package/dist/colors/color-presets.js.map +1 -0
- package/dist/colors/color-theme-helpers.cjs +32 -0
- package/dist/colors/color-theme-helpers.cjs.map +1 -0
- package/dist/colors/color-theme-helpers.d.ts +65 -0
- package/dist/colors/color-theme-helpers.d.ts.map +1 -0
- package/dist/colors/color-theme-helpers.js +32 -0
- package/dist/colors/color-theme-helpers.js.map +1 -0
- package/dist/colors/color-types.cjs +38 -0
- package/dist/colors/color-types.cjs.map +1 -0
- package/dist/colors/color-types.d.ts +112 -0
- package/dist/colors/color-types.d.ts.map +1 -0
- package/dist/colors/color-types.js +38 -0
- package/dist/colors/color-types.js.map +1 -0
- package/dist/colors/color-utils.cjs +197 -0
- package/dist/colors/color-utils.cjs.map +1 -0
- package/dist/colors/color-utils.d.ts +216 -0
- package/dist/colors/color-utils.d.ts.map +1 -0
- package/dist/colors/color-utils.js +197 -0
- package/dist/colors/color-utils.js.map +1 -0
- package/dist/colors/contrast-contracts.cjs +265 -0
- package/dist/colors/contrast-contracts.cjs.map +1 -0
- package/dist/colors/contrast-contracts.d.ts +289 -0
- package/dist/colors/contrast-contracts.d.ts.map +1 -0
- package/dist/colors/contrast-contracts.js +265 -0
- package/dist/colors/contrast-contracts.js.map +1 -0
- package/dist/colors/index.cjs +55 -0
- package/dist/colors/index.cjs.map +1 -0
- package/dist/colors/index.d.ts +16 -0
- package/dist/colors/index.d.ts.map +1 -0
- package/dist/colors/index.js +55 -0
- package/dist/colors/index.js.map +1 -0
- package/dist/core-props.cjs +66 -0
- package/dist/core-props.cjs.map +1 -0
- package/dist/core-props.d.ts +395 -0
- package/dist/core-props.d.ts.map +1 -0
- package/dist/core-props.js +66 -0
- package/dist/core-props.js.map +1 -0
- package/dist/design-tokens/design-token-presets.cjs +91 -0
- package/dist/design-tokens/design-token-presets.cjs.map +1 -0
- package/dist/design-tokens/design-token-presets.d.ts +34 -0
- package/dist/design-tokens/design-token-presets.d.ts.map +1 -0
- package/dist/design-tokens/design-token-presets.js +91 -0
- package/dist/design-tokens/design-token-presets.js.map +1 -0
- package/dist/design-tokens/design-token-types.d.ts +97 -0
- package/dist/design-tokens/design-token-types.d.ts.map +1 -0
- package/dist/design-tokens/index.cjs +10 -0
- package/dist/design-tokens/index.cjs.map +1 -0
- package/dist/design-tokens/index.d.ts +9 -0
- package/dist/design-tokens/index.d.ts.map +1 -0
- package/dist/design-tokens/index.js +10 -0
- package/dist/design-tokens/index.js.map +1 -0
- package/dist/dev-config.cjs +296 -0
- package/dist/dev-config.cjs.map +1 -0
- package/dist/dev-config.d.ts +238 -0
- package/dist/dev-config.d.ts.map +1 -0
- package/dist/dev-config.js +296 -0
- package/dist/dev-config.js.map +1 -0
- package/dist/effects.cjs +69 -0
- package/dist/effects.cjs.map +1 -0
- package/dist/effects.d.ts +152 -0
- package/dist/effects.d.ts.map +1 -0
- package/dist/effects.js +69 -0
- package/dist/effects.js.map +1 -0
- package/dist/global-registry.cjs +25 -0
- package/dist/global-registry.cjs.map +1 -0
- package/dist/global-registry.d.ts +19 -0
- package/dist/global-registry.d.ts.map +1 -0
- package/dist/global-registry.js +25 -0
- package/dist/global-registry.js.map +1 -0
- package/dist/hooks.cjs +378 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.ts +322 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +378 -0
- package/dist/hooks.js.map +1 -0
- package/dist/host-adapter.d.ts +414 -0
- package/dist/host-adapter.d.ts.map +1 -0
- package/dist/index.cjs +229 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +226 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-dev-runtime.cjs +10 -0
- package/dist/jsx-dev-runtime.cjs.map +1 -0
- package/dist/jsx-dev-runtime.d.ts +5 -0
- package/dist/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/jsx-dev-runtime.js +11 -0
- package/dist/jsx-dev-runtime.js.map +1 -0
- package/dist/jsx-runtime.cjs +44 -0
- package/dist/jsx-runtime.cjs.map +1 -0
- package/dist/jsx-runtime.d.ts +24 -0
- package/dist/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx-runtime.js +44 -0
- package/dist/jsx-runtime.js.map +1 -0
- package/dist/jsx-types.d.ts +25 -0
- package/dist/jsx-types.d.ts.map +1 -0
- package/dist/layout/appliers/container-applier.cjs +20 -0
- package/dist/layout/appliers/container-applier.cjs.map +1 -0
- package/dist/layout/appliers/container-applier.d.ts +9 -0
- package/dist/layout/appliers/container-applier.d.ts.map +1 -0
- package/dist/layout/appliers/container-applier.js +20 -0
- package/dist/layout/appliers/container-applier.js.map +1 -0
- package/dist/layout/appliers/position-applier.cjs +31 -0
- package/dist/layout/appliers/position-applier.cjs.map +1 -0
- package/dist/layout/appliers/position-applier.d.ts +8 -0
- package/dist/layout/appliers/position-applier.d.ts.map +1 -0
- package/dist/layout/appliers/position-applier.js +31 -0
- package/dist/layout/appliers/position-applier.js.map +1 -0
- package/dist/layout/layout-engine-test-utils.d.ts +26 -0
- package/dist/layout/layout-engine-test-utils.d.ts.map +1 -0
- package/dist/layout/layout-engine.cjs +628 -0
- package/dist/layout/layout-engine.cjs.map +1 -0
- package/dist/layout/layout-engine.d.ts +140 -0
- package/dist/layout/layout-engine.d.ts.map +1 -0
- package/dist/layout/layout-engine.js +628 -0
- package/dist/layout/layout-engine.js.map +1 -0
- package/dist/layout/strategies/base-strategy.cjs +31 -0
- package/dist/layout/strategies/base-strategy.cjs.map +1 -0
- package/dist/layout/strategies/base-strategy.d.ts +59 -0
- package/dist/layout/strategies/base-strategy.d.ts.map +1 -0
- package/dist/layout/strategies/base-strategy.js +31 -0
- package/dist/layout/strategies/base-strategy.js.map +1 -0
- package/dist/layout/strategies/column-layout.cjs +145 -0
- package/dist/layout/strategies/column-layout.cjs.map +1 -0
- package/dist/layout/strategies/column-layout.d.ts +38 -0
- package/dist/layout/strategies/column-layout.d.ts.map +1 -0
- package/dist/layout/strategies/column-layout.js +145 -0
- package/dist/layout/strategies/column-layout.js.map +1 -0
- package/dist/layout/strategies/row-layout.cjs +145 -0
- package/dist/layout/strategies/row-layout.cjs.map +1 -0
- package/dist/layout/strategies/row-layout.d.ts +38 -0
- package/dist/layout/strategies/row-layout.d.ts.map +1 -0
- package/dist/layout/strategies/row-layout.js +145 -0
- package/dist/layout/strategies/row-layout.js.map +1 -0
- package/dist/layout/strategies/stack-layout.cjs +94 -0
- package/dist/layout/strategies/stack-layout.cjs.map +1 -0
- package/dist/layout/strategies/stack-layout.d.ts +30 -0
- package/dist/layout/strategies/stack-layout.d.ts.map +1 -0
- package/dist/layout/strategies/stack-layout.js +94 -0
- package/dist/layout/strategies/stack-layout.js.map +1 -0
- package/dist/layout/types.d.ts +134 -0
- package/dist/layout/types.d.ts.map +1 -0
- package/dist/layout/utils/child-utils.cjs +129 -0
- package/dist/layout/utils/child-utils.cjs.map +1 -0
- package/dist/layout/utils/child-utils.d.ts +54 -0
- package/dist/layout/utils/child-utils.d.ts.map +1 -0
- package/dist/layout/utils/child-utils.js +129 -0
- package/dist/layout/utils/child-utils.js.map +1 -0
- package/dist/layout/utils/dimension-calculator.cjs +109 -0
- package/dist/layout/utils/dimension-calculator.cjs.map +1 -0
- package/dist/layout/utils/dimension-calculator.d.ts +59 -0
- package/dist/layout/utils/dimension-calculator.d.ts.map +1 -0
- package/dist/layout/utils/dimension-calculator.js +109 -0
- package/dist/layout/utils/dimension-calculator.js.map +1 -0
- package/dist/layout/utils/flex-distributor.cjs +173 -0
- package/dist/layout/utils/flex-distributor.cjs.map +1 -0
- package/dist/layout/utils/flex-distributor.d.ts +18 -0
- package/dist/layout/utils/flex-distributor.d.ts.map +1 -0
- package/dist/layout/utils/flex-distributor.js +173 -0
- package/dist/layout/utils/flex-distributor.js.map +1 -0
- package/dist/layout/utils/size-resolver.cjs +280 -0
- package/dist/layout/utils/size-resolver.cjs.map +1 -0
- package/dist/layout/utils/size-resolver.d.ts +84 -0
- package/dist/layout/utils/size-resolver.d.ts.map +1 -0
- package/dist/layout/utils/size-resolver.js +280 -0
- package/dist/layout/utils/size-resolver.js.map +1 -0
- package/dist/layout/utils/spacing-calculator.cjs +50 -0
- package/dist/layout/utils/spacing-calculator.cjs.map +1 -0
- package/dist/layout/utils/spacing-calculator.d.ts +27 -0
- package/dist/layout/utils/spacing-calculator.d.ts.map +1 -0
- package/dist/layout/utils/spacing-calculator.js +50 -0
- package/dist/layout/utils/spacing-calculator.js.map +1 -0
- package/dist/memo.cjs +18 -0
- package/dist/memo.cjs.map +1 -0
- package/dist/memo.d.ts +29 -0
- package/dist/memo.d.ts.map +1 -0
- package/dist/memo.js +18 -0
- package/dist/memo.js.map +1 -0
- package/dist/nineslice-contract.cjs +60 -0
- package/dist/nineslice-contract.cjs.map +1 -0
- package/dist/nineslice-contract.d.ts +107 -0
- package/dist/nineslice-contract.d.ts.map +1 -0
- package/dist/nineslice-contract.js +60 -0
- package/dist/nineslice-contract.js.map +1 -0
- package/dist/placeholder.cjs +12 -0
- package/dist/placeholder.cjs.map +1 -0
- package/dist/placeholder.d.ts +44 -0
- package/dist/placeholder.d.ts.map +1 -0
- package/dist/placeholder.js +12 -0
- package/dist/placeholder.js.map +1 -0
- package/dist/portal.cjs +89 -0
- package/dist/portal.cjs.map +1 -0
- package/dist/portal.d.ts +62 -0
- package/dist/portal.d.ts.map +1 -0
- package/dist/portal.js +89 -0
- package/dist/portal.js.map +1 -0
- package/dist/primitive-contracts.cjs +12 -0
- package/dist/primitive-contracts.cjs.map +1 -0
- package/dist/primitive-contracts.d.ts +186 -0
- package/dist/primitive-contracts.d.ts.map +1 -0
- package/dist/primitive-contracts.js +12 -0
- package/dist/primitive-contracts.js.map +1 -0
- package/dist/theme.cjs +332 -0
- package/dist/theme.cjs.map +1 -0
- package/dist/theme.d.ts +204 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +332 -0
- package/dist/theme.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/vdom/create-runtime.cjs +79 -0
- package/dist/vdom/create-runtime.cjs.map +1 -0
- package/dist/vdom/create-runtime.d.ts +7 -0
- package/dist/vdom/create-runtime.d.ts.map +1 -0
- package/dist/vdom/create-runtime.js +79 -0
- package/dist/vdom/create-runtime.js.map +1 -0
- package/dist/vdom/index.cjs +8 -0
- package/dist/vdom/index.cjs.map +1 -0
- package/dist/vdom/index.d.ts +4 -0
- package/dist/vdom/index.d.ts.map +1 -0
- package/dist/vdom/index.js +8 -0
- package/dist/vdom/index.js.map +1 -0
- package/dist/vdom/mount.cjs +161 -0
- package/dist/vdom/mount.cjs.map +1 -0
- package/dist/vdom/mount.d.ts +6 -0
- package/dist/vdom/mount.d.ts.map +1 -0
- package/dist/vdom/mount.js +161 -0
- package/dist/vdom/mount.js.map +1 -0
- package/dist/vdom/patch.cjs +163 -0
- package/dist/vdom/patch.cjs.map +1 -0
- package/dist/vdom/patch.d.ts +3 -0
- package/dist/vdom/patch.d.ts.map +1 -0
- package/dist/vdom/patch.js +163 -0
- package/dist/vdom/patch.js.map +1 -0
- package/dist/vdom/registry.cjs +85 -0
- package/dist/vdom/registry.cjs.map +1 -0
- package/dist/vdom/registry.d.ts +28 -0
- package/dist/vdom/registry.d.ts.map +1 -0
- package/dist/vdom/registry.js +85 -0
- package/dist/vdom/registry.js.map +1 -0
- package/dist/vdom/runtime-helpers.cjs +23 -0
- package/dist/vdom/runtime-helpers.cjs.map +1 -0
- package/dist/vdom/runtime-helpers.d.ts +8 -0
- package/dist/vdom/runtime-helpers.d.ts.map +1 -0
- package/dist/vdom/runtime-helpers.js +23 -0
- package/dist/vdom/runtime-helpers.js.map +1 -0
- package/dist/vdom/surface.cjs +107 -0
- package/dist/vdom/surface.cjs.map +1 -0
- package/dist/vdom/surface.d.ts +9 -0
- package/dist/vdom/surface.d.ts.map +1 -0
- package/dist/vdom/surface.js +107 -0
- package/dist/vdom/surface.js.map +1 -0
- package/dist/vdom/types.d.ts +104 -0
- package/dist/vdom/types.d.ts.map +1 -0
- package/dist/vdom/utils.cjs +146 -0
- package/dist/vdom/utils.cjs.map +1 -0
- package/dist/vdom/utils.d.ts +24 -0
- package/dist/vdom/utils.d.ts.map +1 -0
- package/dist/vdom/utils.js +146 -0
- package/dist/vdom/utils.js.map +1 -0
- package/dist/vdom.d.ts +4 -0
- package/dist/vdom.d.ts.map +1 -0
- package/dist/vector-draw-context.d.ts +63 -0
- package/dist/vector-draw-context.d.ts.map +1 -0
- package/package.json +161 -0
- package/vdom/index.cjs +1 -0
- package/vdom/index.d.ts +1 -0
- package/vdom/index.js +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-engine.cjs","sources":["../../src/animation/effect-engine.ts"],"sourcesContent":["/**\n * Central effect engine — runs EffectDefinitions against EffectTargets.\n *\n * The effect engine is the heart of the motion system. It interprets\n * effect definitions (pure data) and drives them against renderer-specific\n * targets using the shared tween/physics primitives.\n *\n * Renderers only implement EffectTarget — the engine handles everything else.\n */\n\nimport type { HostScheduler } from '../host-adapter'\nimport { createSpring, type SpringHandle } from './create-spring'\nimport type { EffectDefinition, EffectStep, NoiseStep } from './effect-definitions'\nimport { createTween, type TweenHandle } from './tween'\nimport type { AnimValues, EffectConfig } from './types'\n\n// ---------------------------------------------------------------------------\n// EffectTarget — what renderers implement\n// ---------------------------------------------------------------------------\n\n/**\n * Contract between the central effect engine and a renderer.\n *\n * Renderers (Pixi, Phaser) implement this to connect Core effects\n * to native nodes. The engine calls these methods to read/apply values.\n *\n * Portable components can also implement EffectTarget to use effects\n * without depending on any renderer bridge. See `applyEffect()` in\n * `@number10/jsx-core` for the 4-arg overload.\n *\n * @example\n * ```typescript\n * // Portable component effect target\n * const target: EffectTarget = {\n * onUpdate: (values) => {\n * if (values.x !== undefined) node.x = values.x\n * if (values.y !== undefined) node.y = values.y\n * if (values.alpha !== undefined) node.alpha = values.alpha\n * },\n * getSnapshot: () => ({\n * x: node.x, y: node.y, alpha: node.alpha,\n * scaleX: node.scaleX, scaleY: node.scaleY,\n * rotation: node.rotation,\n * }),\n * getScheduler: () => surface.scheduler,\n * getSize: () => ({ width: node.width, height: node.height }),\n * }\n * ```\n */\nexport interface EffectTarget {\n /** Apply partial values to the native node */\n onUpdate(values: Partial<AnimValues>): void\n /** Read current values from the native node (for snapshot-based effects) */\n getSnapshot(): AnimValues\n /** Get the HostScheduler for frame updates */\n getScheduler(): HostScheduler\n /** Optional: size for origin-aware transform calculation */\n getSize?(): { width: number; height: number }\n}\n\n// ---------------------------------------------------------------------------\n// EffectHandle\n// ---------------------------------------------------------------------------\n\n/**\n * Handle to an active effect — allows stopping and checking status.\n */\nexport interface EffectHandle {\n /** Stop the effect immediately. onComplete is NOT called. */\n stop(): void\n /** Whether the effect is still running */\n readonly isActive: boolean\n}\n\n// ---------------------------------------------------------------------------\n// Internal state management\n// ---------------------------------------------------------------------------\n\ninterface EffectState {\n activeTweens: Set<TweenHandle<AnimValues>>\n activeSprings: Set<SpringHandle<AnimValues>>\n base: AnimValues\n animatedKeys: Set<keyof AnimValues>\n token: number\n}\n\nconst effectStates = new WeakMap<object, EffectState>()\n\nfunction getState(key: object, snapshot: AnimValues): EffectState {\n let state = effectStates.get(key)\n if (!state) {\n state = {\n activeTweens: new Set(),\n activeSprings: new Set(),\n base: { ...snapshot },\n animatedKeys: new Set(),\n token: 0,\n }\n effectStates.set(key, state)\n }\n return state\n}\n\nfunction pickAnimatedValues(\n values: Partial<AnimValues>,\n keys: Iterable<keyof AnimValues>\n): Partial<AnimValues> {\n const partial: Partial<AnimValues> = {}\n for (const key of keys) {\n const value = values[key]\n if (value !== undefined) {\n partial[key] = value\n }\n }\n return partial\n}\n\nfunction collectStepAnimatedKeys(step: EffectStep): Set<keyof AnimValues> {\n if (step.type === 'noise') {\n return new Set<keyof AnimValues>(['x', 'y'])\n }\n\n const keys = new Set<keyof AnimValues>()\n for (const key of Object.keys(step.to) as (keyof AnimValues)[]) {\n keys.add(key)\n }\n\n const fromValues = 'from' in step ? step.from : undefined\n if (fromValues) {\n for (const key of Object.keys(fromValues) as (keyof AnimValues)[]) {\n keys.add(key)\n }\n }\n\n return keys\n}\n\nfunction stopTargetEffects(state: EffectState): void {\n for (const t of state.activeTweens) t.stop()\n state.activeTweens.clear()\n for (const s of state.activeSprings) s.stop()\n state.activeSprings.clear()\n}\n\n// ---------------------------------------------------------------------------\n// runEffect\n// ---------------------------------------------------------------------------\n\n/**\n * Run an effect against a target.\n *\n * @param targetKey - Object used as WeakMap key (typically the renderer node)\n * @param target - EffectTarget implementation\n * @param definition - Effect definition (steps, loop, origin)\n * @param config - Runtime configuration (intensity, time, etc.)\n * @returns EffectHandle for stopping and status checking\n */\nexport function runEffect(\n targetKey: object,\n target: EffectTarget,\n definition: EffectDefinition,\n config: EffectConfig\n): EffectHandle {\n const scheduler = target.getScheduler()\n\n // Preserve original base from any existing effect — this is critical\n // for correct \"return to original\" behavior when effects are restarted\n // mid-animation (e.g., rapid button clicks).\n const existingState = effectStates.get(targetKey)\n const originalBase: AnimValues = existingState\n ? { ...existingState.base }\n : { ...target.getSnapshot() }\n\n // Stop any running effect and reset target to original base\n if (existingState) {\n stopTargetEffects(existingState)\n target.onUpdate(pickAnimatedValues(originalBase, existingState.animatedKeys))\n effectStates.delete(targetKey)\n }\n\n // Create fresh state with the preserved original base\n const freshState = getState(targetKey, originalBase)\n freshState.base = { ...originalBase }\n freshState.token++\n\n const token = freshState.token\n const steps: EffectStep[] =\n typeof definition.steps === 'function'\n ? definition.steps(freshState.base, config)\n : definition.steps\n const effectAnimatedKeys = new Set<keyof AnimValues>()\n for (const step of steps) {\n for (const key of collectStepAnimatedKeys(step)) {\n effectAnimatedKeys.add(key)\n }\n }\n freshState.animatedKeys = effectAnimatedKeys\n\n let completed = false\n\n const runSteps = (index: number): void => {\n if (completed || freshState.token !== token) return\n if (index >= steps.length) {\n // Finite effect: reset to base values\n if (!definition.loop) {\n target.onUpdate(pickAnimatedValues(freshState.base, freshState.animatedKeys))\n }\n completed = true\n config.onComplete?.()\n return\n }\n\n const step = steps[index]\n if (!step) {\n runSteps(index + 1)\n return\n }\n const stepAnimatedKeys = collectStepAnimatedKeys(step)\n\n const currentSnapshot = target.getSnapshot()\n const fromValues = 'from' in step ? step.from : undefined\n const start = {\n ...currentSnapshot,\n ...(fromValues ?? {}),\n } as AnimValues\n\n // Apply optional \"from\" values immediately\n if (fromValues) {\n target.onUpdate(fromValues)\n }\n\n if (step.type === 'noise') {\n runNoiseStep(freshState, token, target, scheduler, step, () => runSteps(index + 1))\n } else if (step.type === 'tween') {\n const handle = createTween(\n start,\n {\n to: step.to,\n duration: step.duration,\n ease: step.ease,\n onUpdate: (values) => {\n if (freshState.token !== token) {\n handle.stop()\n return\n }\n target.onUpdate(pickAnimatedValues(values, stepAnimatedKeys))\n },\n onComplete: () => {\n freshState.activeTweens.delete(handle)\n if (freshState.token === token) runSteps(index + 1)\n },\n },\n scheduler\n )\n freshState.activeTweens.add(handle)\n } else if (step.type === 'spring') {\n const handle = createSpring(\n start,\n {\n to: step.to,\n config: step.config,\n onUpdate: (values) => {\n if (freshState.token !== token) {\n handle.stop()\n return\n }\n target.onUpdate(pickAnimatedValues(values, stepAnimatedKeys))\n },\n onComplete: () => {\n freshState.activeSprings.delete(handle)\n if (freshState.token === token) runSteps(index + 1)\n },\n },\n scheduler\n )\n freshState.activeSprings.add(handle)\n }\n }\n\n // Start the first step synchronously (frame scheduling is inside createTween)\n runSteps(0)\n\n return {\n stop: () => {\n if (completed) return\n completed = true\n stopTargetEffects(freshState)\n // Reset target to original base values before cleaning up,\n // otherwise rapid re-triggers would snapshot an intermediate position.\n target.onUpdate(pickAnimatedValues(freshState.base, freshState.animatedKeys))\n effectStates.delete(targetKey)\n },\n get isActive() {\n return !completed\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Noise step runner\n// ---------------------------------------------------------------------------\n\nfunction runNoiseStep(\n state: EffectState,\n token: number,\n target: EffectTarget,\n scheduler: HostScheduler,\n step: NoiseStep,\n onDone: () => void\n): void {\n const startTime = performance.now()\n const handle = scheduler.onFrame(() => {\n if (state.token !== token) {\n handle.cancel()\n return\n }\n const elapsed = performance.now() - startTime\n const progress = Math.min(elapsed / step.duration, 1)\n const mag = step.magnitude * step.decay(progress)\n target.onUpdate({\n x: state.base.x + (Math.random() * 2 - 1) * mag,\n y: state.base.y + (Math.random() * 2 - 1) * mag,\n })\n if (progress >= 1) {\n handle.cancel()\n onDone()\n }\n })\n}\n\n// ---------------------------------------------------------------------------\n// stopEffect\n// ---------------------------------------------------------------------------\n\n/**\n * Stop all active effects for the given target key.\n * Resets the target to its original base values.\n */\nexport function stopEffect(targetKey: object): void {\n const state = effectStates.get(targetKey)\n if (state) {\n stopTargetEffects(state)\n effectStates.delete(targetKey)\n }\n}\n"],"names":["createTween","createSpring"],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { HostScheduler } from '../host-adapter';
|
|
2
|
+
import { EffectDefinition } from './effect-definitions';
|
|
3
|
+
import { AnimValues, EffectConfig } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Contract between the central effect engine and a renderer.
|
|
6
|
+
*
|
|
7
|
+
* Renderers (Pixi, Phaser) implement this to connect Core effects
|
|
8
|
+
* to native nodes. The engine calls these methods to read/apply values.
|
|
9
|
+
*
|
|
10
|
+
* Portable components can also implement EffectTarget to use effects
|
|
11
|
+
* without depending on any renderer bridge. See `applyEffect()` in
|
|
12
|
+
* `@number10/jsx-core` for the 4-arg overload.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Portable component effect target
|
|
17
|
+
* const target: EffectTarget = {
|
|
18
|
+
* onUpdate: (values) => {
|
|
19
|
+
* if (values.x !== undefined) node.x = values.x
|
|
20
|
+
* if (values.y !== undefined) node.y = values.y
|
|
21
|
+
* if (values.alpha !== undefined) node.alpha = values.alpha
|
|
22
|
+
* },
|
|
23
|
+
* getSnapshot: () => ({
|
|
24
|
+
* x: node.x, y: node.y, alpha: node.alpha,
|
|
25
|
+
* scaleX: node.scaleX, scaleY: node.scaleY,
|
|
26
|
+
* rotation: node.rotation,
|
|
27
|
+
* }),
|
|
28
|
+
* getScheduler: () => surface.scheduler,
|
|
29
|
+
* getSize: () => ({ width: node.width, height: node.height }),
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export interface EffectTarget {
|
|
34
|
+
/** Apply partial values to the native node */
|
|
35
|
+
onUpdate(values: Partial<AnimValues>): void;
|
|
36
|
+
/** Read current values from the native node (for snapshot-based effects) */
|
|
37
|
+
getSnapshot(): AnimValues;
|
|
38
|
+
/** Get the HostScheduler for frame updates */
|
|
39
|
+
getScheduler(): HostScheduler;
|
|
40
|
+
/** Optional: size for origin-aware transform calculation */
|
|
41
|
+
getSize?(): {
|
|
42
|
+
width: number;
|
|
43
|
+
height: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Handle to an active effect — allows stopping and checking status.
|
|
48
|
+
*/
|
|
49
|
+
export interface EffectHandle {
|
|
50
|
+
/** Stop the effect immediately. onComplete is NOT called. */
|
|
51
|
+
stop(): void;
|
|
52
|
+
/** Whether the effect is still running */
|
|
53
|
+
readonly isActive: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Run an effect against a target.
|
|
57
|
+
*
|
|
58
|
+
* @param targetKey - Object used as WeakMap key (typically the renderer node)
|
|
59
|
+
* @param target - EffectTarget implementation
|
|
60
|
+
* @param definition - Effect definition (steps, loop, origin)
|
|
61
|
+
* @param config - Runtime configuration (intensity, time, etc.)
|
|
62
|
+
* @returns EffectHandle for stopping and status checking
|
|
63
|
+
*/
|
|
64
|
+
export declare function runEffect(targetKey: object, target: EffectTarget, definition: EffectDefinition, config: EffectConfig): EffectHandle;
|
|
65
|
+
/**
|
|
66
|
+
* Stop all active effects for the given target key.
|
|
67
|
+
* Resets the target to its original base values.
|
|
68
|
+
*/
|
|
69
|
+
export declare function stopEffect(targetKey: object): void;
|
|
70
|
+
//# sourceMappingURL=effect-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-engine.d.ts","sourceRoot":"","sources":["../../src/animation/effect-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,KAAK,EAAE,gBAAgB,EAAyB,MAAM,sBAAsB,CAAA;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAMvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAA;IAC3C,4EAA4E;IAC5E,WAAW,IAAI,UAAU,CAAA;IACzB,8CAA8C;IAC9C,YAAY,IAAI,aAAa,CAAA;IAC7B,4DAA4D;IAC5D,OAAO,CAAC,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9C;AAMD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,IAAI,IAAI,IAAI,CAAA;IACZ,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAC3B;AA4ED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,gBAAgB,EAC5B,MAAM,EAAE,YAAY,GACnB,YAAY,CAsId;AAsCD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAMlD"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { createSpring } from "./create-spring.js";
|
|
2
|
+
import { createTween } from "./tween.js";
|
|
3
|
+
const effectStates = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function getState(key, snapshot) {
|
|
5
|
+
let state = effectStates.get(key);
|
|
6
|
+
if (!state) {
|
|
7
|
+
state = {
|
|
8
|
+
activeTweens: /* @__PURE__ */ new Set(),
|
|
9
|
+
activeSprings: /* @__PURE__ */ new Set(),
|
|
10
|
+
base: { ...snapshot },
|
|
11
|
+
animatedKeys: /* @__PURE__ */ new Set(),
|
|
12
|
+
token: 0
|
|
13
|
+
};
|
|
14
|
+
effectStates.set(key, state);
|
|
15
|
+
}
|
|
16
|
+
return state;
|
|
17
|
+
}
|
|
18
|
+
function pickAnimatedValues(values, keys) {
|
|
19
|
+
const partial = {};
|
|
20
|
+
for (const key of keys) {
|
|
21
|
+
const value = values[key];
|
|
22
|
+
if (value !== void 0) {
|
|
23
|
+
partial[key] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return partial;
|
|
27
|
+
}
|
|
28
|
+
function collectStepAnimatedKeys(step) {
|
|
29
|
+
if (step.type === "noise") {
|
|
30
|
+
return /* @__PURE__ */ new Set(["x", "y"]);
|
|
31
|
+
}
|
|
32
|
+
const keys = /* @__PURE__ */ new Set();
|
|
33
|
+
for (const key of Object.keys(step.to)) {
|
|
34
|
+
keys.add(key);
|
|
35
|
+
}
|
|
36
|
+
const fromValues = "from" in step ? step.from : void 0;
|
|
37
|
+
if (fromValues) {
|
|
38
|
+
for (const key of Object.keys(fromValues)) {
|
|
39
|
+
keys.add(key);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return keys;
|
|
43
|
+
}
|
|
44
|
+
function stopTargetEffects(state) {
|
|
45
|
+
for (const t of state.activeTweens) t.stop();
|
|
46
|
+
state.activeTweens.clear();
|
|
47
|
+
for (const s of state.activeSprings) s.stop();
|
|
48
|
+
state.activeSprings.clear();
|
|
49
|
+
}
|
|
50
|
+
function runEffect(targetKey, target, definition, config) {
|
|
51
|
+
const scheduler = target.getScheduler();
|
|
52
|
+
const existingState = effectStates.get(targetKey);
|
|
53
|
+
const originalBase = existingState ? { ...existingState.base } : { ...target.getSnapshot() };
|
|
54
|
+
if (existingState) {
|
|
55
|
+
stopTargetEffects(existingState);
|
|
56
|
+
target.onUpdate(pickAnimatedValues(originalBase, existingState.animatedKeys));
|
|
57
|
+
effectStates.delete(targetKey);
|
|
58
|
+
}
|
|
59
|
+
const freshState = getState(targetKey, originalBase);
|
|
60
|
+
freshState.base = { ...originalBase };
|
|
61
|
+
freshState.token++;
|
|
62
|
+
const token = freshState.token;
|
|
63
|
+
const steps = typeof definition.steps === "function" ? definition.steps(freshState.base, config) : definition.steps;
|
|
64
|
+
const effectAnimatedKeys = /* @__PURE__ */ new Set();
|
|
65
|
+
for (const step of steps) {
|
|
66
|
+
for (const key of collectStepAnimatedKeys(step)) {
|
|
67
|
+
effectAnimatedKeys.add(key);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
freshState.animatedKeys = effectAnimatedKeys;
|
|
71
|
+
let completed = false;
|
|
72
|
+
const runSteps = (index) => {
|
|
73
|
+
if (completed || freshState.token !== token) return;
|
|
74
|
+
if (index >= steps.length) {
|
|
75
|
+
if (!definition.loop) {
|
|
76
|
+
target.onUpdate(pickAnimatedValues(freshState.base, freshState.animatedKeys));
|
|
77
|
+
}
|
|
78
|
+
completed = true;
|
|
79
|
+
config.onComplete?.();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const step = steps[index];
|
|
83
|
+
if (!step) {
|
|
84
|
+
runSteps(index + 1);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const stepAnimatedKeys = collectStepAnimatedKeys(step);
|
|
88
|
+
const currentSnapshot = target.getSnapshot();
|
|
89
|
+
const fromValues = "from" in step ? step.from : void 0;
|
|
90
|
+
const start = {
|
|
91
|
+
...currentSnapshot,
|
|
92
|
+
...fromValues ?? {}
|
|
93
|
+
};
|
|
94
|
+
if (fromValues) {
|
|
95
|
+
target.onUpdate(fromValues);
|
|
96
|
+
}
|
|
97
|
+
if (step.type === "noise") {
|
|
98
|
+
runNoiseStep(freshState, token, target, scheduler, step, () => runSteps(index + 1));
|
|
99
|
+
} else if (step.type === "tween") {
|
|
100
|
+
const handle = createTween(
|
|
101
|
+
start,
|
|
102
|
+
{
|
|
103
|
+
to: step.to,
|
|
104
|
+
duration: step.duration,
|
|
105
|
+
ease: step.ease,
|
|
106
|
+
onUpdate: (values) => {
|
|
107
|
+
if (freshState.token !== token) {
|
|
108
|
+
handle.stop();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
target.onUpdate(pickAnimatedValues(values, stepAnimatedKeys));
|
|
112
|
+
},
|
|
113
|
+
onComplete: () => {
|
|
114
|
+
freshState.activeTweens.delete(handle);
|
|
115
|
+
if (freshState.token === token) runSteps(index + 1);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
scheduler
|
|
119
|
+
);
|
|
120
|
+
freshState.activeTweens.add(handle);
|
|
121
|
+
} else if (step.type === "spring") {
|
|
122
|
+
const handle = createSpring(
|
|
123
|
+
start,
|
|
124
|
+
{
|
|
125
|
+
to: step.to,
|
|
126
|
+
config: step.config,
|
|
127
|
+
onUpdate: (values) => {
|
|
128
|
+
if (freshState.token !== token) {
|
|
129
|
+
handle.stop();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
target.onUpdate(pickAnimatedValues(values, stepAnimatedKeys));
|
|
133
|
+
},
|
|
134
|
+
onComplete: () => {
|
|
135
|
+
freshState.activeSprings.delete(handle);
|
|
136
|
+
if (freshState.token === token) runSteps(index + 1);
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
scheduler
|
|
140
|
+
);
|
|
141
|
+
freshState.activeSprings.add(handle);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
runSteps(0);
|
|
145
|
+
return {
|
|
146
|
+
stop: () => {
|
|
147
|
+
if (completed) return;
|
|
148
|
+
completed = true;
|
|
149
|
+
stopTargetEffects(freshState);
|
|
150
|
+
target.onUpdate(pickAnimatedValues(freshState.base, freshState.animatedKeys));
|
|
151
|
+
effectStates.delete(targetKey);
|
|
152
|
+
},
|
|
153
|
+
get isActive() {
|
|
154
|
+
return !completed;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function runNoiseStep(state, token, target, scheduler, step, onDone) {
|
|
159
|
+
const startTime = performance.now();
|
|
160
|
+
const handle = scheduler.onFrame(() => {
|
|
161
|
+
if (state.token !== token) {
|
|
162
|
+
handle.cancel();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const elapsed = performance.now() - startTime;
|
|
166
|
+
const progress = Math.min(elapsed / step.duration, 1);
|
|
167
|
+
const mag = step.magnitude * step.decay(progress);
|
|
168
|
+
target.onUpdate({
|
|
169
|
+
x: state.base.x + (Math.random() * 2 - 1) * mag,
|
|
170
|
+
y: state.base.y + (Math.random() * 2 - 1) * mag
|
|
171
|
+
});
|
|
172
|
+
if (progress >= 1) {
|
|
173
|
+
handle.cancel();
|
|
174
|
+
onDone();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function stopEffect(targetKey) {
|
|
179
|
+
const state = effectStates.get(targetKey);
|
|
180
|
+
if (state) {
|
|
181
|
+
stopTargetEffects(state);
|
|
182
|
+
effectStates.delete(targetKey);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
export {
|
|
186
|
+
runEffect,
|
|
187
|
+
stopEffect
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=effect-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-engine.js","sources":["../../src/animation/effect-engine.ts"],"sourcesContent":["/**\n * Central effect engine — runs EffectDefinitions against EffectTargets.\n *\n * The effect engine is the heart of the motion system. It interprets\n * effect definitions (pure data) and drives them against renderer-specific\n * targets using the shared tween/physics primitives.\n *\n * Renderers only implement EffectTarget — the engine handles everything else.\n */\n\nimport type { HostScheduler } from '../host-adapter'\nimport { createSpring, type SpringHandle } from './create-spring'\nimport type { EffectDefinition, EffectStep, NoiseStep } from './effect-definitions'\nimport { createTween, type TweenHandle } from './tween'\nimport type { AnimValues, EffectConfig } from './types'\n\n// ---------------------------------------------------------------------------\n// EffectTarget — what renderers implement\n// ---------------------------------------------------------------------------\n\n/**\n * Contract between the central effect engine and a renderer.\n *\n * Renderers (Pixi, Phaser) implement this to connect Core effects\n * to native nodes. The engine calls these methods to read/apply values.\n *\n * Portable components can also implement EffectTarget to use effects\n * without depending on any renderer bridge. See `applyEffect()` in\n * `@number10/jsx-core` for the 4-arg overload.\n *\n * @example\n * ```typescript\n * // Portable component effect target\n * const target: EffectTarget = {\n * onUpdate: (values) => {\n * if (values.x !== undefined) node.x = values.x\n * if (values.y !== undefined) node.y = values.y\n * if (values.alpha !== undefined) node.alpha = values.alpha\n * },\n * getSnapshot: () => ({\n * x: node.x, y: node.y, alpha: node.alpha,\n * scaleX: node.scaleX, scaleY: node.scaleY,\n * rotation: node.rotation,\n * }),\n * getScheduler: () => surface.scheduler,\n * getSize: () => ({ width: node.width, height: node.height }),\n * }\n * ```\n */\nexport interface EffectTarget {\n /** Apply partial values to the native node */\n onUpdate(values: Partial<AnimValues>): void\n /** Read current values from the native node (for snapshot-based effects) */\n getSnapshot(): AnimValues\n /** Get the HostScheduler for frame updates */\n getScheduler(): HostScheduler\n /** Optional: size for origin-aware transform calculation */\n getSize?(): { width: number; height: number }\n}\n\n// ---------------------------------------------------------------------------\n// EffectHandle\n// ---------------------------------------------------------------------------\n\n/**\n * Handle to an active effect — allows stopping and checking status.\n */\nexport interface EffectHandle {\n /** Stop the effect immediately. onComplete is NOT called. */\n stop(): void\n /** Whether the effect is still running */\n readonly isActive: boolean\n}\n\n// ---------------------------------------------------------------------------\n// Internal state management\n// ---------------------------------------------------------------------------\n\ninterface EffectState {\n activeTweens: Set<TweenHandle<AnimValues>>\n activeSprings: Set<SpringHandle<AnimValues>>\n base: AnimValues\n animatedKeys: Set<keyof AnimValues>\n token: number\n}\n\nconst effectStates = new WeakMap<object, EffectState>()\n\nfunction getState(key: object, snapshot: AnimValues): EffectState {\n let state = effectStates.get(key)\n if (!state) {\n state = {\n activeTweens: new Set(),\n activeSprings: new Set(),\n base: { ...snapshot },\n animatedKeys: new Set(),\n token: 0,\n }\n effectStates.set(key, state)\n }\n return state\n}\n\nfunction pickAnimatedValues(\n values: Partial<AnimValues>,\n keys: Iterable<keyof AnimValues>\n): Partial<AnimValues> {\n const partial: Partial<AnimValues> = {}\n for (const key of keys) {\n const value = values[key]\n if (value !== undefined) {\n partial[key] = value\n }\n }\n return partial\n}\n\nfunction collectStepAnimatedKeys(step: EffectStep): Set<keyof AnimValues> {\n if (step.type === 'noise') {\n return new Set<keyof AnimValues>(['x', 'y'])\n }\n\n const keys = new Set<keyof AnimValues>()\n for (const key of Object.keys(step.to) as (keyof AnimValues)[]) {\n keys.add(key)\n }\n\n const fromValues = 'from' in step ? step.from : undefined\n if (fromValues) {\n for (const key of Object.keys(fromValues) as (keyof AnimValues)[]) {\n keys.add(key)\n }\n }\n\n return keys\n}\n\nfunction stopTargetEffects(state: EffectState): void {\n for (const t of state.activeTweens) t.stop()\n state.activeTweens.clear()\n for (const s of state.activeSprings) s.stop()\n state.activeSprings.clear()\n}\n\n// ---------------------------------------------------------------------------\n// runEffect\n// ---------------------------------------------------------------------------\n\n/**\n * Run an effect against a target.\n *\n * @param targetKey - Object used as WeakMap key (typically the renderer node)\n * @param target - EffectTarget implementation\n * @param definition - Effect definition (steps, loop, origin)\n * @param config - Runtime configuration (intensity, time, etc.)\n * @returns EffectHandle for stopping and status checking\n */\nexport function runEffect(\n targetKey: object,\n target: EffectTarget,\n definition: EffectDefinition,\n config: EffectConfig\n): EffectHandle {\n const scheduler = target.getScheduler()\n\n // Preserve original base from any existing effect — this is critical\n // for correct \"return to original\" behavior when effects are restarted\n // mid-animation (e.g., rapid button clicks).\n const existingState = effectStates.get(targetKey)\n const originalBase: AnimValues = existingState\n ? { ...existingState.base }\n : { ...target.getSnapshot() }\n\n // Stop any running effect and reset target to original base\n if (existingState) {\n stopTargetEffects(existingState)\n target.onUpdate(pickAnimatedValues(originalBase, existingState.animatedKeys))\n effectStates.delete(targetKey)\n }\n\n // Create fresh state with the preserved original base\n const freshState = getState(targetKey, originalBase)\n freshState.base = { ...originalBase }\n freshState.token++\n\n const token = freshState.token\n const steps: EffectStep[] =\n typeof definition.steps === 'function'\n ? definition.steps(freshState.base, config)\n : definition.steps\n const effectAnimatedKeys = new Set<keyof AnimValues>()\n for (const step of steps) {\n for (const key of collectStepAnimatedKeys(step)) {\n effectAnimatedKeys.add(key)\n }\n }\n freshState.animatedKeys = effectAnimatedKeys\n\n let completed = false\n\n const runSteps = (index: number): void => {\n if (completed || freshState.token !== token) return\n if (index >= steps.length) {\n // Finite effect: reset to base values\n if (!definition.loop) {\n target.onUpdate(pickAnimatedValues(freshState.base, freshState.animatedKeys))\n }\n completed = true\n config.onComplete?.()\n return\n }\n\n const step = steps[index]\n if (!step) {\n runSteps(index + 1)\n return\n }\n const stepAnimatedKeys = collectStepAnimatedKeys(step)\n\n const currentSnapshot = target.getSnapshot()\n const fromValues = 'from' in step ? step.from : undefined\n const start = {\n ...currentSnapshot,\n ...(fromValues ?? {}),\n } as AnimValues\n\n // Apply optional \"from\" values immediately\n if (fromValues) {\n target.onUpdate(fromValues)\n }\n\n if (step.type === 'noise') {\n runNoiseStep(freshState, token, target, scheduler, step, () => runSteps(index + 1))\n } else if (step.type === 'tween') {\n const handle = createTween(\n start,\n {\n to: step.to,\n duration: step.duration,\n ease: step.ease,\n onUpdate: (values) => {\n if (freshState.token !== token) {\n handle.stop()\n return\n }\n target.onUpdate(pickAnimatedValues(values, stepAnimatedKeys))\n },\n onComplete: () => {\n freshState.activeTweens.delete(handle)\n if (freshState.token === token) runSteps(index + 1)\n },\n },\n scheduler\n )\n freshState.activeTweens.add(handle)\n } else if (step.type === 'spring') {\n const handle = createSpring(\n start,\n {\n to: step.to,\n config: step.config,\n onUpdate: (values) => {\n if (freshState.token !== token) {\n handle.stop()\n return\n }\n target.onUpdate(pickAnimatedValues(values, stepAnimatedKeys))\n },\n onComplete: () => {\n freshState.activeSprings.delete(handle)\n if (freshState.token === token) runSteps(index + 1)\n },\n },\n scheduler\n )\n freshState.activeSprings.add(handle)\n }\n }\n\n // Start the first step synchronously (frame scheduling is inside createTween)\n runSteps(0)\n\n return {\n stop: () => {\n if (completed) return\n completed = true\n stopTargetEffects(freshState)\n // Reset target to original base values before cleaning up,\n // otherwise rapid re-triggers would snapshot an intermediate position.\n target.onUpdate(pickAnimatedValues(freshState.base, freshState.animatedKeys))\n effectStates.delete(targetKey)\n },\n get isActive() {\n return !completed\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Noise step runner\n// ---------------------------------------------------------------------------\n\nfunction runNoiseStep(\n state: EffectState,\n token: number,\n target: EffectTarget,\n scheduler: HostScheduler,\n step: NoiseStep,\n onDone: () => void\n): void {\n const startTime = performance.now()\n const handle = scheduler.onFrame(() => {\n if (state.token !== token) {\n handle.cancel()\n return\n }\n const elapsed = performance.now() - startTime\n const progress = Math.min(elapsed / step.duration, 1)\n const mag = step.magnitude * step.decay(progress)\n target.onUpdate({\n x: state.base.x + (Math.random() * 2 - 1) * mag,\n y: state.base.y + (Math.random() * 2 - 1) * mag,\n })\n if (progress >= 1) {\n handle.cancel()\n onDone()\n }\n })\n}\n\n// ---------------------------------------------------------------------------\n// stopEffect\n// ---------------------------------------------------------------------------\n\n/**\n * Stop all active effects for the given target key.\n * Resets the target to its original base values.\n */\nexport function stopEffect(targetKey: object): void {\n const state = effectStates.get(targetKey)\n if (state) {\n stopTargetEffects(state)\n effectStates.delete(targetKey)\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation utilities — @number10/jsx-core
|
|
3
|
+
*
|
|
4
|
+
* Three complementary animation approaches:
|
|
5
|
+
* - createTween / useTween: time-based duration+easing interpolation
|
|
6
|
+
* - createSpring / useSpring: physics-based spring animation via signals
|
|
7
|
+
*
|
|
8
|
+
* Effect system (migration target):
|
|
9
|
+
* - types: AnimValues, EffectConfig
|
|
10
|
+
* - easing: Complete Penner equations
|
|
11
|
+
* - effect-definitions: 23 built-in effects as pure data
|
|
12
|
+
* - effect-engine: Central effect runner with EffectTarget contract
|
|
13
|
+
*/
|
|
14
|
+
export * from './animated-signal';
|
|
15
|
+
export { createSpring, type SpringAnimationConfig, type SpringHandle } from './create-spring';
|
|
16
|
+
export { Easing, type EasingFn } from './easing';
|
|
17
|
+
export { EFFECT_DEFINITIONS, resolveEffectTransformOrigin, type EffectDefinition, type EffectStep, type EffectTransformOrigin, type NoiseStep, type SpringStep, type TweenStep, } from './effect-definitions';
|
|
18
|
+
export { runEffect, stopEffect, type EffectHandle, type EffectTarget } from './effect-engine';
|
|
19
|
+
export * from './spring-physics';
|
|
20
|
+
export * from './tween';
|
|
21
|
+
export type { AnimValues, EffectConfig } from './types';
|
|
22
|
+
export * from './useSpring';
|
|
23
|
+
export { TWEEN_PRESETS, useTween, useTweens, type TweenAnimationStep, type TweenConfig, type TweenPreset, } from './useTween';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,mBAAmB,CAAA;AACjC,OAAO,EAAE,YAAY,EAAE,KAAK,qBAAqB,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC7F,OAAO,EAAE,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC5B,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC7F,cAAc,kBAAkB,CAAA;AAChC,cAAc,SAAS,CAAA;AACvB,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACvD,cAAc,aAAa,CAAA;AAC3B,OAAO,EACL,aAAa,EACb,QAAQ,EACR,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const DEFAULT_SPRING_CONFIG = {
|
|
4
|
+
tension: 170,
|
|
5
|
+
friction: 26,
|
|
6
|
+
mass: 1,
|
|
7
|
+
restVelocity: 0.01,
|
|
8
|
+
restDelta: 0.01,
|
|
9
|
+
clamp: false
|
|
10
|
+
};
|
|
11
|
+
const SPRING_PRESETS = {
|
|
12
|
+
/** Gentle, but still responsive animation */
|
|
13
|
+
gentle: { tension: 350, friction: 24, restVelocity: 0.5, restDelta: 0.1 },
|
|
14
|
+
/** Moderate, balanced animation (default) */
|
|
15
|
+
default: { tension: 600, friction: 40, restVelocity: 0.5, restDelta: 0.1 },
|
|
16
|
+
/** Bouncy, playful animation tuned for quick UI feedback */
|
|
17
|
+
wobbly: { tension: 900, friction: 35, restVelocity: 0.5, restDelta: 0.1 },
|
|
18
|
+
/** Very fast, snappy response for press/pulse-style interactions */
|
|
19
|
+
stiff: { tension: 1800, friction: 60, restVelocity: 0.5, restDelta: 0.1 },
|
|
20
|
+
/** Slow, deliberate animation */
|
|
21
|
+
slow: { tension: 350, friction: 48, restVelocity: 0.5, restDelta: 0.1 },
|
|
22
|
+
/** Nearly instant transition */
|
|
23
|
+
instant: { tension: 2500, friction: 90, restVelocity: 1, restDelta: 0.02, clamp: true }
|
|
24
|
+
};
|
|
25
|
+
class SpringPhysics {
|
|
26
|
+
config;
|
|
27
|
+
/**
|
|
28
|
+
* Creates a new spring physics engine
|
|
29
|
+
* @param config - Spring configuration
|
|
30
|
+
*/
|
|
31
|
+
constructor(config = {}) {
|
|
32
|
+
this.config = { ...DEFAULT_SPRING_CONFIG, ...config };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Updates spring configuration
|
|
36
|
+
* @param config - Partial config to merge with current
|
|
37
|
+
*/
|
|
38
|
+
updateConfig(config) {
|
|
39
|
+
this.config = { ...this.config, ...config };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Performs one physics step
|
|
43
|
+
* Uses semi-implicit Euler integration for stability
|
|
44
|
+
* @param state - Current spring state
|
|
45
|
+
* @param target - Target value
|
|
46
|
+
* @param deltaTime - Time delta in seconds
|
|
47
|
+
* @returns New spring state
|
|
48
|
+
*/
|
|
49
|
+
step(state, target, deltaTime) {
|
|
50
|
+
const { tension, friction, mass, clamp } = this.config;
|
|
51
|
+
const springForce = -tension * (state.value - target);
|
|
52
|
+
const dampingForce = -friction * state.velocity;
|
|
53
|
+
const acceleration = (springForce + dampingForce) / mass;
|
|
54
|
+
const newVelocity = state.velocity + acceleration * deltaTime;
|
|
55
|
+
let newValue = state.value + newVelocity * deltaTime;
|
|
56
|
+
if (clamp) {
|
|
57
|
+
const min = Math.min(state.value, target);
|
|
58
|
+
const max = Math.max(state.value, target);
|
|
59
|
+
newValue = Math.max(min, Math.min(max, newValue));
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
value: newValue,
|
|
63
|
+
velocity: newVelocity
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Checks if spring has reached rest state
|
|
68
|
+
* @param state - Current spring state
|
|
69
|
+
* @param target - Target value
|
|
70
|
+
* @returns True if spring is at rest
|
|
71
|
+
*/
|
|
72
|
+
isAtRest(state, target) {
|
|
73
|
+
const { restVelocity, restDelta } = this.config;
|
|
74
|
+
const isVelocitySmall = Math.abs(state.velocity) <= restVelocity;
|
|
75
|
+
const isDisplacementSmall = Math.abs(state.value - target) <= restDelta;
|
|
76
|
+
return isVelocitySmall && isDisplacementSmall;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Snaps spring to target if at rest
|
|
80
|
+
* @param state - Current spring state
|
|
81
|
+
* @param target - Target value
|
|
82
|
+
* @returns Adjusted state (snapped if at rest)
|
|
83
|
+
*/
|
|
84
|
+
snapIfAtRest(state, target) {
|
|
85
|
+
if (this.isAtRest(state, target)) {
|
|
86
|
+
return { value: target, velocity: 0 };
|
|
87
|
+
}
|
|
88
|
+
return state;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.DEFAULT_SPRING_CONFIG = DEFAULT_SPRING_CONFIG;
|
|
92
|
+
exports.SPRING_PRESETS = SPRING_PRESETS;
|
|
93
|
+
exports.SpringPhysics = SpringPhysics;
|
|
94
|
+
//# sourceMappingURL=spring-physics.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spring-physics.cjs","sources":["../../src/animation/spring-physics.ts"],"sourcesContent":["/**\n * Spring physics engine for smooth, natural animations\n * Based on spring-damper system with configurable tension, friction, and mass\n *\n * @migration(audit:surface-access) Phase 7 — moved to @number10/jsx-core ✅\n */\n\n/**\n * Configuration for spring physics behavior\n */\nexport interface SpringConfig {\n /** Spring stiffness (higher = faster, snappier). Default: 170 */\n tension?: number\n /** Damping force (higher = less oscillation). Default: 26 */\n friction?: number\n /** Mass of the animated object (higher = slower). Default: 1 */\n mass?: number\n /** Velocity threshold below which animation stops. Default: 0.01 */\n restVelocity?: number\n /** Distance threshold below which animation stops. Default: 0.01 */\n restDelta?: number\n /** Clamp values to prevent overshoot. Default: false */\n clamp?: boolean\n /**\n * Called once when the spring starts moving from rest.\n * Fires BEFORE the first physics step.\n */\n onStart?: (() => void) | undefined\n /**\n * Called on every frame with the current spring value.\n * Useful for syncing non-signal state.\n */\n onUpdate?: ((value: number) => void) | undefined\n}\n\n/**\n * Spring physics state\n */\nexport interface SpringState {\n /** Current value */\n value: number\n /** Current velocity */\n velocity: number\n}\n\n/**\n * Default spring configuration (similar to react-spring)\n */\nexport const DEFAULT_SPRING_CONFIG: Required<Omit<SpringConfig, 'onStart' | 'onUpdate'>> = {\n tension: 170,\n friction: 26,\n mass: 1,\n restVelocity: 0.01,\n restDelta: 0.01,\n clamp: false,\n}\n\n/**\n * Preset spring configurations for common use cases\n * Note: clamp prevents overshoot but can make animations feel less natural\n * For UI animations, consider enabling clamp to prevent visual artifacts\n */\nexport const SPRING_PRESETS = {\n /** Gentle, but still responsive animation */\n gentle: { tension: 350, friction: 24, restVelocity: 0.5, restDelta: 0.1 },\n /** Moderate, balanced animation (default) */\n default: { tension: 600, friction: 40, restVelocity: 0.5, restDelta: 0.1 },\n /** Bouncy, playful animation tuned for quick UI feedback */\n wobbly: { tension: 900, friction: 35, restVelocity: 0.5, restDelta: 0.1 },\n /** Very fast, snappy response for press/pulse-style interactions */\n stiff: { tension: 1800, friction: 60, restVelocity: 0.5, restDelta: 0.1 },\n /** Slow, deliberate animation */\n slow: { tension: 350, friction: 48, restVelocity: 0.5, restDelta: 0.1 },\n /** Nearly instant transition */\n instant: { tension: 2500, friction: 90, restVelocity: 1, restDelta: 0.02, clamp: true },\n} as const\n\n/**\n * Type for animation preset keys\n */\nexport type AnimationPreset = keyof typeof SPRING_PRESETS\n/**\n * Type for animation configuration (preset name or custom config)\n */\nexport type AnimationConfig = AnimationPreset | SpringConfig\n\n/**\n * Spring physics engine\n * Implements spring-damper physics for smooth, natural animations\n */\nexport class SpringPhysics {\n private config: Required<Omit<SpringConfig, 'onStart' | 'onUpdate'>> &\n Pick<SpringConfig, 'onStart' | 'onUpdate'>\n\n /**\n * Creates a new spring physics engine\n * @param config - Spring configuration\n */\n constructor(config: SpringConfig = {}) {\n this.config = { ...DEFAULT_SPRING_CONFIG, ...config } as typeof this.config\n }\n\n /**\n * Updates spring configuration\n * @param config - Partial config to merge with current\n */\n updateConfig(config: Partial<SpringConfig>): void {\n this.config = { ...this.config, ...config } as typeof this.config\n }\n\n /**\n * Performs one physics step\n * Uses semi-implicit Euler integration for stability\n * @param state - Current spring state\n * @param target - Target value\n * @param deltaTime - Time delta in seconds\n * @returns New spring state\n */\n step(state: SpringState, target: number, deltaTime: number): SpringState {\n const { tension, friction, mass, clamp } = this.config\n\n // Calculate spring force (Hooke's law)\n const springForce = -tension * (state.value - target)\n\n // Calculate damping force\n const dampingForce = -friction * state.velocity\n\n // Calculate acceleration (F = ma → a = F/m)\n const acceleration = (springForce + dampingForce) / mass\n\n // Update velocity (semi-implicit Euler)\n const newVelocity = state.velocity + acceleration * deltaTime\n\n // Update position\n let newValue = state.value + newVelocity * deltaTime\n\n // Clamp if enabled\n if (clamp) {\n const min = Math.min(state.value, target)\n const max = Math.max(state.value, target)\n newValue = Math.max(min, Math.min(max, newValue))\n }\n\n return {\n value: newValue,\n velocity: newVelocity,\n }\n }\n\n /**\n * Checks if spring has reached rest state\n * @param state - Current spring state\n * @param target - Target value\n * @returns True if spring is at rest\n */\n isAtRest(state: SpringState, target: number): boolean {\n const { restVelocity, restDelta } = this.config\n const isVelocitySmall = Math.abs(state.velocity) <= restVelocity\n const isDisplacementSmall = Math.abs(state.value - target) <= restDelta\n return isVelocitySmall && isDisplacementSmall\n }\n\n /**\n * Snaps spring to target if at rest\n * @param state - Current spring state\n * @param target - Target value\n * @returns Adjusted state (snapped if at rest)\n */\n snapIfAtRest(state: SpringState, target: number): SpringState {\n if (this.isAtRest(state, target)) {\n return { value: target, velocity: 0 }\n }\n return state\n }\n}\n"],"names":[],"mappings":";;AAgDO,MAAM,wBAA8E;AAAA,EACzF,SAAS;AAAA,EACT,UAAU;AAAA,EACV,MAAM;AAAA,EACN,cAAc;AAAA,EACd,WAAW;AAAA,EACX,OAAO;AACT;AAOO,MAAM,iBAAiB;AAAA;AAAA,EAE5B,QAAQ,EAAE,SAAS,KAAK,UAAU,IAAI,cAAc,KAAK,WAAW,IAAA;AAAA;AAAA,EAEpE,SAAS,EAAE,SAAS,KAAK,UAAU,IAAI,cAAc,KAAK,WAAW,IAAA;AAAA;AAAA,EAErE,QAAQ,EAAE,SAAS,KAAK,UAAU,IAAI,cAAc,KAAK,WAAW,IAAA;AAAA;AAAA,EAEpE,OAAO,EAAE,SAAS,MAAM,UAAU,IAAI,cAAc,KAAK,WAAW,IAAA;AAAA;AAAA,EAEpE,MAAM,EAAE,SAAS,KAAK,UAAU,IAAI,cAAc,KAAK,WAAW,IAAA;AAAA;AAAA,EAElE,SAAS,EAAE,SAAS,MAAM,UAAU,IAAI,cAAc,GAAG,WAAW,MAAM,OAAO,KAAA;AACnF;AAeO,MAAM,cAAc;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA,EAOR,YAAY,SAAuB,IAAI;AACrC,SAAK,SAAS,EAAE,GAAG,uBAAuB,GAAG,OAAA;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,QAAqC;AAChD,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAG,OAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,KAAK,OAAoB,QAAgB,WAAgC;AACvE,UAAM,EAAE,SAAS,UAAU,MAAM,MAAA,IAAU,KAAK;AAGhD,UAAM,cAAc,CAAC,WAAW,MAAM,QAAQ;AAG9C,UAAM,eAAe,CAAC,WAAW,MAAM;AAGvC,UAAM,gBAAgB,cAAc,gBAAgB;AAGpD,UAAM,cAAc,MAAM,WAAW,eAAe;AAGpD,QAAI,WAAW,MAAM,QAAQ,cAAc;AAG3C,QAAI,OAAO;AACT,YAAM,MAAM,KAAK,IAAI,MAAM,OAAO,MAAM;AACxC,YAAM,MAAM,KAAK,IAAI,MAAM,OAAO,MAAM;AACxC,iBAAW,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,QAAQ,CAAC;AAAA,IAClD;AAEA,WAAO;AAAA,MACL,OAAO;AAAA,MACP,UAAU;AAAA,IAAA;AAAA,EAEd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,OAAoB,QAAyB;AACpD,UAAM,EAAE,cAAc,UAAA,IAAc,KAAK;AACzC,UAAM,kBAAkB,KAAK,IAAI,MAAM,QAAQ,KAAK;AACpD,UAAM,sBAAsB,KAAK,IAAI,MAAM,QAAQ,MAAM,KAAK;AAC9D,WAAO,mBAAmB;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,OAAoB,QAA6B;AAC5D,QAAI,KAAK,SAAS,OAAO,MAAM,GAAG;AAChC,aAAO,EAAE,OAAO,QAAQ,UAAU,EAAA;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AACF;;;;"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spring physics engine for smooth, natural animations
|
|
3
|
+
* Based on spring-damper system with configurable tension, friction, and mass
|
|
4
|
+
*
|
|
5
|
+
* @migration(audit:surface-access) Phase 7 — moved to @number10/jsx-core ✅
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for spring physics behavior
|
|
9
|
+
*/
|
|
10
|
+
export interface SpringConfig {
|
|
11
|
+
/** Spring stiffness (higher = faster, snappier). Default: 170 */
|
|
12
|
+
tension?: number;
|
|
13
|
+
/** Damping force (higher = less oscillation). Default: 26 */
|
|
14
|
+
friction?: number;
|
|
15
|
+
/** Mass of the animated object (higher = slower). Default: 1 */
|
|
16
|
+
mass?: number;
|
|
17
|
+
/** Velocity threshold below which animation stops. Default: 0.01 */
|
|
18
|
+
restVelocity?: number;
|
|
19
|
+
/** Distance threshold below which animation stops. Default: 0.01 */
|
|
20
|
+
restDelta?: number;
|
|
21
|
+
/** Clamp values to prevent overshoot. Default: false */
|
|
22
|
+
clamp?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Called once when the spring starts moving from rest.
|
|
25
|
+
* Fires BEFORE the first physics step.
|
|
26
|
+
*/
|
|
27
|
+
onStart?: (() => void) | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Called on every frame with the current spring value.
|
|
30
|
+
* Useful for syncing non-signal state.
|
|
31
|
+
*/
|
|
32
|
+
onUpdate?: ((value: number) => void) | undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Spring physics state
|
|
36
|
+
*/
|
|
37
|
+
export interface SpringState {
|
|
38
|
+
/** Current value */
|
|
39
|
+
value: number;
|
|
40
|
+
/** Current velocity */
|
|
41
|
+
velocity: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Default spring configuration (similar to react-spring)
|
|
45
|
+
*/
|
|
46
|
+
export declare const DEFAULT_SPRING_CONFIG: Required<Omit<SpringConfig, 'onStart' | 'onUpdate'>>;
|
|
47
|
+
/**
|
|
48
|
+
* Preset spring configurations for common use cases
|
|
49
|
+
* Note: clamp prevents overshoot but can make animations feel less natural
|
|
50
|
+
* For UI animations, consider enabling clamp to prevent visual artifacts
|
|
51
|
+
*/
|
|
52
|
+
export declare const SPRING_PRESETS: {
|
|
53
|
+
/** Gentle, but still responsive animation */
|
|
54
|
+
readonly gentle: {
|
|
55
|
+
readonly tension: 350;
|
|
56
|
+
readonly friction: 24;
|
|
57
|
+
readonly restVelocity: 0.5;
|
|
58
|
+
readonly restDelta: 0.1;
|
|
59
|
+
};
|
|
60
|
+
/** Moderate, balanced animation (default) */
|
|
61
|
+
readonly default: {
|
|
62
|
+
readonly tension: 600;
|
|
63
|
+
readonly friction: 40;
|
|
64
|
+
readonly restVelocity: 0.5;
|
|
65
|
+
readonly restDelta: 0.1;
|
|
66
|
+
};
|
|
67
|
+
/** Bouncy, playful animation tuned for quick UI feedback */
|
|
68
|
+
readonly wobbly: {
|
|
69
|
+
readonly tension: 900;
|
|
70
|
+
readonly friction: 35;
|
|
71
|
+
readonly restVelocity: 0.5;
|
|
72
|
+
readonly restDelta: 0.1;
|
|
73
|
+
};
|
|
74
|
+
/** Very fast, snappy response for press/pulse-style interactions */
|
|
75
|
+
readonly stiff: {
|
|
76
|
+
readonly tension: 1800;
|
|
77
|
+
readonly friction: 60;
|
|
78
|
+
readonly restVelocity: 0.5;
|
|
79
|
+
readonly restDelta: 0.1;
|
|
80
|
+
};
|
|
81
|
+
/** Slow, deliberate animation */
|
|
82
|
+
readonly slow: {
|
|
83
|
+
readonly tension: 350;
|
|
84
|
+
readonly friction: 48;
|
|
85
|
+
readonly restVelocity: 0.5;
|
|
86
|
+
readonly restDelta: 0.1;
|
|
87
|
+
};
|
|
88
|
+
/** Nearly instant transition */
|
|
89
|
+
readonly instant: {
|
|
90
|
+
readonly tension: 2500;
|
|
91
|
+
readonly friction: 90;
|
|
92
|
+
readonly restVelocity: 1;
|
|
93
|
+
readonly restDelta: 0.02;
|
|
94
|
+
readonly clamp: true;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Type for animation preset keys
|
|
99
|
+
*/
|
|
100
|
+
export type AnimationPreset = keyof typeof SPRING_PRESETS;
|
|
101
|
+
/**
|
|
102
|
+
* Type for animation configuration (preset name or custom config)
|
|
103
|
+
*/
|
|
104
|
+
export type AnimationConfig = AnimationPreset | SpringConfig;
|
|
105
|
+
/**
|
|
106
|
+
* Spring physics engine
|
|
107
|
+
* Implements spring-damper physics for smooth, natural animations
|
|
108
|
+
*/
|
|
109
|
+
export declare class SpringPhysics {
|
|
110
|
+
private config;
|
|
111
|
+
/**
|
|
112
|
+
* Creates a new spring physics engine
|
|
113
|
+
* @param config - Spring configuration
|
|
114
|
+
*/
|
|
115
|
+
constructor(config?: SpringConfig);
|
|
116
|
+
/**
|
|
117
|
+
* Updates spring configuration
|
|
118
|
+
* @param config - Partial config to merge with current
|
|
119
|
+
*/
|
|
120
|
+
updateConfig(config: Partial<SpringConfig>): void;
|
|
121
|
+
/**
|
|
122
|
+
* Performs one physics step
|
|
123
|
+
* Uses semi-implicit Euler integration for stability
|
|
124
|
+
* @param state - Current spring state
|
|
125
|
+
* @param target - Target value
|
|
126
|
+
* @param deltaTime - Time delta in seconds
|
|
127
|
+
* @returns New spring state
|
|
128
|
+
*/
|
|
129
|
+
step(state: SpringState, target: number, deltaTime: number): SpringState;
|
|
130
|
+
/**
|
|
131
|
+
* Checks if spring has reached rest state
|
|
132
|
+
* @param state - Current spring state
|
|
133
|
+
* @param target - Target value
|
|
134
|
+
* @returns True if spring is at rest
|
|
135
|
+
*/
|
|
136
|
+
isAtRest(state: SpringState, target: number): boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Snaps spring to target if at rest
|
|
139
|
+
* @param state - Current spring state
|
|
140
|
+
* @param target - Target value
|
|
141
|
+
* @returns Adjusted state (snapped if at rest)
|
|
142
|
+
*/
|
|
143
|
+
snapIfAtRest(state: SpringState, target: number): SpringState;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=spring-physics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spring-physics.d.ts","sourceRoot":"","sources":["../../src/animation/spring-physics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;CACjD;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,UAAU,CAAC,CAOtF,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc;IACzB,6CAA6C;;;;;;;IAE7C,6CAA6C;;;;;;;IAE7C,4DAA4D;;;;;;;IAE5D,oEAAoE;;;;;;;IAEpE,iCAAiC;;;;;;;IAEjC,gCAAgC;;;;;;;;CAExB,CAAA;AAEV;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,cAAc,CAAA;AACzD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,YAAY,CAAA;AAE5D;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAC8B;IAE5C;;;OAGG;gBACS,MAAM,GAAE,YAAiB;IAIrC;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAIjD;;;;;;;OAOG;IACH,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW;IA+BxE;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAOrD;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW;CAM9D"}
|