@simpludify/core 0.0.0-stage → 0.1.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 +21 -0
- package/README.md +21 -3
- package/dist/animation/actor-tween.d.ts +10 -0
- package/dist/animation/sprite-animation.d.ts +62 -0
- package/dist/components.d.ts +2 -0
- package/dist/foundation/cancellation.d.ts +13 -0
- package/dist/foundation/diagnostics.d.ts +10 -0
- package/dist/foundation/easing.d.ts +11 -0
- package/dist/foundation/events.d.ts +18 -0
- package/dist/foundation/grid.d.ts +22 -0
- package/dist/foundation/lifetime.d.ts +14 -0
- package/dist/foundation/random.d.ts +44 -0
- package/dist/foundation/timers.d.ts +11 -0
- package/dist/foundation/tween.d.ts +159 -0
- package/dist/foundation/version.d.ts +2 -0
- package/dist/game/character.d.ts +21 -0
- package/dist/game/collider.d.ts +58 -0
- package/dist/game/collision-body.d.ts +18 -0
- package/dist/game/collision-contact.d.ts +15 -0
- package/dist/game/collision-geometry.d.ts +36 -0
- package/dist/game/collision-policy.d.ts +15 -0
- package/dist/game/collision-response.d.ts +4 -0
- package/dist/game/collision.d.ts +110 -0
- package/dist/game/geometry-tilemap.d.ts +78 -0
- package/dist/game/motion.d.ts +43 -0
- package/dist/game/tile-collision-geometry.d.ts +29 -0
- package/dist/game/tile-collision-index.d.ts +34 -0
- package/dist/game/tile-contact.d.ts +18 -0
- package/dist/game/tilemap-collision.d.ts +34 -0
- package/dist/game/tilemap.d.ts +104 -0
- package/dist/graphics/camera-follow.d.ts +19 -0
- package/dist/graphics/components.d.ts +105 -0
- package/dist/graphics/coordinates.d.ts +68 -0
- package/dist/graphics/sprite-sheet.d.ts +41 -0
- package/dist/graphics/tile-geometry.d.ts +47 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +8121 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction/action-bindings.d.ts +51 -0
- package/dist/interaction/action-frame.d.ts +19 -0
- package/dist/interaction/action-types.d.ts +35 -0
- package/dist/interaction/actions.d.ts +109 -0
- package/dist/interaction/input-source.d.ts +12 -0
- package/dist/interaction/input.d.ts +52 -0
- package/dist/interaction/key-code.d.ts +189 -0
- package/dist/interaction/pointer-routing.d.ts +91 -0
- package/dist/runtime/engine.d.ts +52 -0
- package/dist/runtime/fixed-step.d.ts +25 -0
- package/dist/runtime/ports.d.ts +19 -0
- package/dist/runtime/replay-data.d.ts +39 -0
- package/dist/runtime/replay.d.ts +74 -0
- package/dist/scene/actor.d.ts +54 -0
- package/dist/scene/component.d.ts +43 -0
- package/dist/scene/execution.d.ts +10 -0
- package/dist/scene/scene.d.ts +79 -0
- package/dist/ui/canvas-control.d.ts +60 -0
- package/dist/ui/canvas-editor.d.ts +36 -0
- package/dist/ui/canvas-input.d.ts +117 -0
- package/dist/ui/canvas-layout.d.ts +14 -0
- package/dist/ui/canvas-node.d.ts +196 -0
- package/dist/ui/canvas-number-input.d.ts +26 -0
- package/dist/ui/canvas-select.d.ts +32 -0
- package/dist/ui/canvas-text-input.d.ts +23 -0
- package/dist/ui/canvas-text.d.ts +5 -0
- package/dist/ui/canvas-tween.d.ts +10 -0
- package/dist/ui/canvas-ui.d.ts +89 -0
- package/dist/ui/native-edit.d.ts +28 -0
- package/dist/ui/scrollbar.d.ts +13 -0
- package/package.json +44 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 oz-coden
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# @simpludify/core
|
|
2
|
+
|
|
3
|
+
Experimental v0.1.0 of Simpludify, a code-first TypeScript 2D engine. APIs may change between 0.x releases. This package contains host-independent Scene/Actor/Component, collision, geometry, tilemaps, tween/animation, input and Canvas UI models. It has no browser or Node runtime dependencies.
|
|
4
|
+
|
|
5
|
+
The v0.1.0 distribution is being prepared; registry availability is not yet confirmed. Once published:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @simpludify/core@0.1.0
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import { Engine, Actor, Transform } from "@simpludify/core";
|
|
13
|
+
const engine = new Engine();
|
|
14
|
+
const actor = new Actor();
|
|
15
|
+
actor.add(new Transform({ x: 10, y: 20 }));
|
|
16
|
+
engine.scene.add(actor);
|
|
17
|
+
engine.step(1 / 60);
|
|
18
|
+
engine.dispose();
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
ESM only, ES2022, Node >=22.12 for headless usage. No CommonJS or renderer is included. For browser presentation install `@simpludify/web`, which depends on this package. JavaScript source maps embed the original sources; declarations are included. [Repository and API](https://github.com/oz-coden/Simpludify) · [Documentation](https://github.oz-coden.com/Simpludify/). MIT.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Actor } from "../scene/actor.js";
|
|
2
|
+
/** Explicit draw-only channels. World Transform/Motion/CollisionBody are never tweened. */
|
|
3
|
+
export declare function actorTween(actor: Actor): Readonly<{
|
|
4
|
+
offsetX: import("../index.js").TweenBinding;
|
|
5
|
+
offsetY: import("../index.js").TweenBinding;
|
|
6
|
+
rotation: import("../index.js").TweenBinding;
|
|
7
|
+
scaleX: import("../index.js").TweenBinding;
|
|
8
|
+
scaleY: import("../index.js").TweenBinding;
|
|
9
|
+
opacity: import("../index.js").TweenBinding;
|
|
10
|
+
}>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { SpriteSheet } from "../graphics/sprite-sheet.js";
|
|
2
|
+
import { Component, type ComponentType, type UpdateContext } from "../scene/component.js";
|
|
3
|
+
/** Uniform frame timing in simulation seconds; default 8fps and loop=true. */
|
|
4
|
+
export type SpriteClip<FrameName extends string = never> = Readonly<{
|
|
5
|
+
frames: readonly (number | FrameName)[];
|
|
6
|
+
loop?: boolean;
|
|
7
|
+
} & ({
|
|
8
|
+
fps?: number;
|
|
9
|
+
frameSeconds?: never;
|
|
10
|
+
} | {
|
|
11
|
+
fps?: never;
|
|
12
|
+
frameSeconds: number;
|
|
13
|
+
})>;
|
|
14
|
+
export declare const SpriteAnimationState: {
|
|
15
|
+
readonly Playing: "playing";
|
|
16
|
+
readonly Paused: "paused";
|
|
17
|
+
readonly Stopped: "stopped";
|
|
18
|
+
readonly Completed: "completed";
|
|
19
|
+
};
|
|
20
|
+
export type SpriteAnimationState = (typeof SpriteAnimationState)[keyof typeof SpriteAnimationState];
|
|
21
|
+
export interface SpriteAnimationOptions<Name extends string, FrameName extends string> {
|
|
22
|
+
sheet: SpriteSheet<FrameName>;
|
|
23
|
+
clips: Readonly<Record<Name, SpriteClip<NoInfer<FrameName>>>>;
|
|
24
|
+
initial?: NoInfer<Name>;
|
|
25
|
+
onComplete?: (name: NoInfer<Name>) => void;
|
|
26
|
+
}
|
|
27
|
+
/** One independent playback cursor per Actor. Requires an existing Renderable. */
|
|
28
|
+
export declare class SpriteAnimation<Name extends string = string, FrameName extends string = never> extends Component {
|
|
29
|
+
static readonly type: ComponentType<SpriteAnimation>;
|
|
30
|
+
readonly type: ComponentType<SpriteAnimation<string, never>>;
|
|
31
|
+
readonly phase: "late-update";
|
|
32
|
+
private readonly clips;
|
|
33
|
+
private readonly complete;
|
|
34
|
+
private selected;
|
|
35
|
+
private clip;
|
|
36
|
+
private status;
|
|
37
|
+
private cursor;
|
|
38
|
+
private time;
|
|
39
|
+
private view;
|
|
40
|
+
private written;
|
|
41
|
+
private image;
|
|
42
|
+
constructor(options: SpriteAnimationOptions<Name, FrameName>);
|
|
43
|
+
get current(): Name;
|
|
44
|
+
get state(): SpriteAnimationState;
|
|
45
|
+
/** Zero-based position within the selected clip, not a sheet index. */
|
|
46
|
+
get frameIndex(): number;
|
|
47
|
+
/** Elapsed simulation seconds within the selected clip; wraps when looping. */
|
|
48
|
+
get elapsed(): number;
|
|
49
|
+
private assertAlive;
|
|
50
|
+
private show;
|
|
51
|
+
protected onAttach(): void;
|
|
52
|
+
/** Same playing/paused clip is a no-op. restart=true or stopped/completed restarts. */
|
|
53
|
+
play(name: Name, options?: {
|
|
54
|
+
restart?: boolean;
|
|
55
|
+
}): void;
|
|
56
|
+
pause(): void;
|
|
57
|
+
resume(): void;
|
|
58
|
+
/** Reset to the first frame; does not emit completion. */
|
|
59
|
+
stop(): void;
|
|
60
|
+
update({ delta }: UpdateContext): void;
|
|
61
|
+
protected onDestroy(): void;
|
|
62
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Owner cancellation, independent of browser AbortSignal and host event types. */
|
|
2
|
+
export interface CancellationSignal {
|
|
3
|
+
readonly aborted: boolean;
|
|
4
|
+
onCancel(callback: () => void): () => void;
|
|
5
|
+
throwIfCancelled(): void;
|
|
6
|
+
}
|
|
7
|
+
export declare class Cancellation {
|
|
8
|
+
private dead;
|
|
9
|
+
private readonly listeners;
|
|
10
|
+
readonly signal: CancellationSignal;
|
|
11
|
+
constructor();
|
|
12
|
+
cancel(): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class EngineError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly details: Readonly<Record<string, unknown>>;
|
|
4
|
+
constructor(code: string, message: string, details?: Readonly<Record<string, unknown>>);
|
|
5
|
+
toJSON(): {
|
|
6
|
+
code: string;
|
|
7
|
+
message: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare function positive(value: number, name: string): number;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Pure normalized easing functions. Custom easing must return a finite value in [0,1]. */
|
|
2
|
+
export type EasingFunction = (progress: number) => number;
|
|
3
|
+
export declare const Easing: Readonly<{
|
|
4
|
+
Linear: (t: number) => number;
|
|
5
|
+
InQuad: (t: number) => number;
|
|
6
|
+
OutQuad: (t: number) => number;
|
|
7
|
+
InOutQuad: (t: number) => number;
|
|
8
|
+
InCubic: (t: number) => number;
|
|
9
|
+
OutCubic: (t: number) => number;
|
|
10
|
+
InOutCubic: (t: number) => number;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type LifetimeOwner } from "./lifetime.js";
|
|
2
|
+
export interface EventType<T> {
|
|
3
|
+
readonly id: symbol;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly payload?: (value: T) => T;
|
|
6
|
+
}
|
|
7
|
+
export declare function defineEvent<T>(name: string): EventType<T>;
|
|
8
|
+
/** Synchronous registration-order delivery. Recursive delivery of the same token is rejected. */
|
|
9
|
+
export declare class EventBus {
|
|
10
|
+
private readonly listeners;
|
|
11
|
+
private readonly dispatching;
|
|
12
|
+
private dead;
|
|
13
|
+
private assertAlive;
|
|
14
|
+
on<T>(type: EventType<T>, handler: (payload: T) => void, owner?: LifetimeOwner): () => void;
|
|
15
|
+
emit<T>(type: EventType<T>, payload: NoInfer<T>): void;
|
|
16
|
+
listenerCount<T>(type?: EventType<T>): number;
|
|
17
|
+
dispose(): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type GridVisitor<T> = (value: T, x: number, y: number) => void;
|
|
2
|
+
/** Fixed-size, row-major data. Cells retain values/references without owning them. */
|
|
3
|
+
export declare class Grid<T> {
|
|
4
|
+
#private;
|
|
5
|
+
static get maxCells(): number;
|
|
6
|
+
/** The same initial value/reference is stored in every cell, including functions. */
|
|
7
|
+
constructor(width: number, height: number, initial: T);
|
|
8
|
+
/** Calls initialize(x,y) once per cell, left-to-right then top-to-bottom. */
|
|
9
|
+
static generate<T>(width: number, height: number, initialize: (x: number, y: number) => T): Grid<T>;
|
|
10
|
+
get width(): number;
|
|
11
|
+
get height(): number;
|
|
12
|
+
/** False for noninteger/nonfinite/out-of-range coordinates; never clips. */
|
|
13
|
+
inBounds(x: number, y: number): boolean;
|
|
14
|
+
get(x: number, y: number): T;
|
|
15
|
+
set(x: number, y: number, value: T): void;
|
|
16
|
+
/** Replaces every cell with the same value/reference; does not dispose old values. */
|
|
17
|
+
fill(value: T): void;
|
|
18
|
+
/** Live row-major traversal; later cells observe writes made by earlier visits. */
|
|
19
|
+
forEach(visit: GridVisitor<T>): void;
|
|
20
|
+
/** Fully contained rectangle, with nonnegative integer extents; empty is valid. */
|
|
21
|
+
forEachRect(x: number, y: number, width: number, height: number, visit: GridVisitor<T>): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface LifetimeOwner {
|
|
2
|
+
readonly disposed: boolean;
|
|
3
|
+
onDispose(callback: () => void): () => void;
|
|
4
|
+
}
|
|
5
|
+
/** Lazy, removable LIFO cleanup. Disposed owners cannot acquire new resources. */
|
|
6
|
+
export declare class Lifetime implements LifetimeOwner {
|
|
7
|
+
private callbacks;
|
|
8
|
+
private dead;
|
|
9
|
+
get disposed(): boolean;
|
|
10
|
+
onDispose(callback: () => void): () => void;
|
|
11
|
+
dispose(): void;
|
|
12
|
+
}
|
|
13
|
+
/** Execute every cleanup even when one throws. */
|
|
14
|
+
export declare function cleanupAll(actions: Iterable<() => void>, message: string): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare const RANDOM_ALGORITHM = "lcg32-fnv1a-utf16le-v1";
|
|
2
|
+
export declare const DEFAULT_RANDOM_STREAM = "$default";
|
|
3
|
+
export interface RandomState {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly seed: number;
|
|
6
|
+
readonly state: number;
|
|
7
|
+
readonly calls: number;
|
|
8
|
+
}
|
|
9
|
+
export interface RandomSnapshot {
|
|
10
|
+
readonly algorithm: typeof RANDOM_ALGORITHM;
|
|
11
|
+
readonly seed: number;
|
|
12
|
+
readonly streams: readonly RandomState[];
|
|
13
|
+
}
|
|
14
|
+
/** FNV-1a over master seed (four LE bytes), then exact UTF-16 code units (two LE bytes each). */
|
|
15
|
+
export declare function deriveStreamSeed(seed: number, name: string): number;
|
|
16
|
+
export declare class RandomStream {
|
|
17
|
+
private readonly initial;
|
|
18
|
+
private current;
|
|
19
|
+
private count;
|
|
20
|
+
private dead;
|
|
21
|
+
/** @internal Streams are acquired from RandomManager.stream(). */
|
|
22
|
+
constructor(initial: number);
|
|
23
|
+
get seed(): number;
|
|
24
|
+
get state(): number;
|
|
25
|
+
get calls(): number;
|
|
26
|
+
get disposed(): boolean;
|
|
27
|
+
next(): number;
|
|
28
|
+
/** @internal */ dispose(): void;
|
|
29
|
+
}
|
|
30
|
+
/** Independent deterministic streams. State survives Scene replacement and ends with its owner. */
|
|
31
|
+
export declare class RandomManager {
|
|
32
|
+
private readonly initial;
|
|
33
|
+
private readonly streams;
|
|
34
|
+
private readonly defaultStream;
|
|
35
|
+
private dead;
|
|
36
|
+
constructor(seed?: number);
|
|
37
|
+
get seed(): number;
|
|
38
|
+
get disposed(): boolean;
|
|
39
|
+
private alive;
|
|
40
|
+
next(): number;
|
|
41
|
+
stream(name: string): RandomStream;
|
|
42
|
+
snapshot(): RandomSnapshot;
|
|
43
|
+
dispose(): void;
|
|
44
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type LifetimeOwner } from "./lifetime.js";
|
|
2
|
+
export declare class SimulationTimers {
|
|
3
|
+
private readonly timers;
|
|
4
|
+
private dead;
|
|
5
|
+
private plan;
|
|
6
|
+
schedule(seconds: number, callback: () => void, repeat: boolean, owner?: LifetimeOwner): () => void;
|
|
7
|
+
/** Capture eligibility before any Scene update phase. */
|
|
8
|
+
beginStep(): void;
|
|
9
|
+
step(seconds: number): void;
|
|
10
|
+
dispose(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { type EasingFunction } from "./easing.js";
|
|
2
|
+
import type { LifetimeOwner } from "./lifetime.js";
|
|
3
|
+
export type TweenCancelReason = "cancelled" | "stopped" | "replaced" | "external-write" | "target-unavailable" | "owner-disposed" | "scheduler-disposed" | "error";
|
|
4
|
+
export interface TweenBindingOptions {
|
|
5
|
+
readonly target: object;
|
|
6
|
+
readonly key: PropertyKey;
|
|
7
|
+
readonly read: () => number;
|
|
8
|
+
readonly write: ((value: number) => void) | ((value: number) => boolean);
|
|
9
|
+
readonly owner?: LifetimeOwner;
|
|
10
|
+
readonly scope?: () => object | undefined;
|
|
11
|
+
readonly valid?: () => boolean;
|
|
12
|
+
readonly validate?: (value: number) => void;
|
|
13
|
+
readonly stamp?: () => unknown;
|
|
14
|
+
readonly watch?: (invalidate: (reason?: TweenCancelReason) => void) => () => void;
|
|
15
|
+
}
|
|
16
|
+
/** Explicit numeric write capability. target/key identifies a channel, not a reflected object path. */
|
|
17
|
+
export declare class TweenBinding {
|
|
18
|
+
readonly options: TweenBindingOptions;
|
|
19
|
+
readonly key: string | symbol;
|
|
20
|
+
constructor(options: TweenBindingOptions);
|
|
21
|
+
}
|
|
22
|
+
export interface TweenOptions {
|
|
23
|
+
readonly duration: number;
|
|
24
|
+
readonly from?: number;
|
|
25
|
+
readonly easing?: EasingFunction;
|
|
26
|
+
readonly delay?: number;
|
|
27
|
+
/** Additional iterations, or Infinity. */
|
|
28
|
+
readonly repeat?: number;
|
|
29
|
+
readonly yoyo?: boolean;
|
|
30
|
+
}
|
|
31
|
+
type NumberRecipe = Readonly<{
|
|
32
|
+
kind: "number";
|
|
33
|
+
binding: TweenBinding;
|
|
34
|
+
to: number;
|
|
35
|
+
duration: number;
|
|
36
|
+
delay: number;
|
|
37
|
+
repeat: number;
|
|
38
|
+
yoyo: boolean;
|
|
39
|
+
easing: EasingFunction;
|
|
40
|
+
from: number | undefined;
|
|
41
|
+
}>;
|
|
42
|
+
export type TweenRecipe = NumberRecipe | Readonly<{
|
|
43
|
+
kind: "delay";
|
|
44
|
+
duration: number;
|
|
45
|
+
}> | Readonly<{
|
|
46
|
+
kind: "sequence" | "parallel";
|
|
47
|
+
children: readonly TweenRecipe[];
|
|
48
|
+
}>;
|
|
49
|
+
export declare function tweenFinite(value: number, label: string): number;
|
|
50
|
+
type Equal<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => (T extends Y ? 1 : 2) ? A : B;
|
|
51
|
+
export type TweenNumericKey<T> = {
|
|
52
|
+
[K in keyof T]-?: T[K] extends number ? Equal<Pick<T, K>, {
|
|
53
|
+
-readonly [P in K]: T[P];
|
|
54
|
+
}, K, never> : never;
|
|
55
|
+
}[keyof T];
|
|
56
|
+
export declare const Tween: Readonly<{
|
|
57
|
+
bind: (options: TweenBindingOptions) => TweenBinding;
|
|
58
|
+
/** Only writable own numeric data properties on plain records. Classes need explicit adapters. */
|
|
59
|
+
property<T extends object>(target: T, key: TweenNumericKey<T>): TweenBinding;
|
|
60
|
+
to(binding: TweenBinding, to: number, options: TweenOptions): TweenRecipe;
|
|
61
|
+
delay: (duration: number) => TweenRecipe;
|
|
62
|
+
sequence: (...children: TweenRecipe[]) => TweenRecipe;
|
|
63
|
+
parallel: (...children: TweenRecipe[]) => TweenRecipe;
|
|
64
|
+
}>;
|
|
65
|
+
interface Track {
|
|
66
|
+
definition: NumberRecipe;
|
|
67
|
+
start: number;
|
|
68
|
+
end: number;
|
|
69
|
+
from: number | undefined;
|
|
70
|
+
done: boolean;
|
|
71
|
+
channel?: Channel | undefined;
|
|
72
|
+
}
|
|
73
|
+
interface Channel {
|
|
74
|
+
binding: TweenBinding;
|
|
75
|
+
expected: number;
|
|
76
|
+
stamp: unknown;
|
|
77
|
+
}
|
|
78
|
+
declare function compile(root: TweenRecipe): {
|
|
79
|
+
duration: number;
|
|
80
|
+
bindings: TweenBinding[];
|
|
81
|
+
tracks: Track[];
|
|
82
|
+
};
|
|
83
|
+
export interface TweenPlayOptions {
|
|
84
|
+
readonly owner?: LifetimeOwner;
|
|
85
|
+
readonly conflict?: "replace" | "error";
|
|
86
|
+
readonly onComplete?: (playback: TweenPlayback) => void;
|
|
87
|
+
readonly onCancel?: (reason: TweenCancelReason, playback: TweenPlayback) => void;
|
|
88
|
+
}
|
|
89
|
+
export type TweenState = "playing" | "paused" | "completed" | "cancelled";
|
|
90
|
+
/** One playback, terminal once. A finished handle drops channels, targets and scheduler references. */
|
|
91
|
+
export declare class TweenPlayback {
|
|
92
|
+
private status;
|
|
93
|
+
private time;
|
|
94
|
+
private updating;
|
|
95
|
+
private cause;
|
|
96
|
+
private removers;
|
|
97
|
+
private channels;
|
|
98
|
+
private tracks;
|
|
99
|
+
private scheduler;
|
|
100
|
+
private complete;
|
|
101
|
+
private cancelled;
|
|
102
|
+
readonly duration: number;
|
|
103
|
+
/** @internal Created by Scheduler.play after recipe validation. */
|
|
104
|
+
constructor(scheduler: TweenScheduler, plan: ReturnType<typeof compile>, options: TweenPlayOptions);
|
|
105
|
+
get state(): TweenState;
|
|
106
|
+
get elapsed(): number;
|
|
107
|
+
get reason(): TweenCancelReason | undefined;
|
|
108
|
+
pause(): void;
|
|
109
|
+
resume(): void;
|
|
110
|
+
cancel(): void;
|
|
111
|
+
stop(): void;
|
|
112
|
+
/** Skip finite delays/iterations and apply terminal values. Infinite playback cannot finish. */
|
|
113
|
+
finish(): void;
|
|
114
|
+
private get terminal();
|
|
115
|
+
/** @internal */ valid(scope: object | undefined): boolean;
|
|
116
|
+
/** @internal */ own(owners: Iterable<LifetimeOwner>): void;
|
|
117
|
+
/** @internal Claims are reserved before replaced-owner callbacks run. */
|
|
118
|
+
claim(): Set<TweenPlayback>;
|
|
119
|
+
/** @internal */ conflicts(): boolean;
|
|
120
|
+
/** @internal */ watch(): void;
|
|
121
|
+
private release;
|
|
122
|
+
private end;
|
|
123
|
+
/** @internal */ interrupt(reason: TweenCancelReason): void;
|
|
124
|
+
/** @internal */ advance(delta: number): void;
|
|
125
|
+
private updateTo;
|
|
126
|
+
private advanceTo;
|
|
127
|
+
}
|
|
128
|
+
/** Explicit clock. Scene owns automatic clocks; standalone schedulers are advanced by their caller. */
|
|
129
|
+
export declare class TweenScheduler {
|
|
130
|
+
private readonly entries;
|
|
131
|
+
private roster;
|
|
132
|
+
private dirty;
|
|
133
|
+
private plan;
|
|
134
|
+
private advancing;
|
|
135
|
+
private dead;
|
|
136
|
+
private rate;
|
|
137
|
+
private owner;
|
|
138
|
+
private removeOwner;
|
|
139
|
+
readonly scope: object | undefined;
|
|
140
|
+
constructor(options?: {
|
|
141
|
+
owner?: LifetimeOwner;
|
|
142
|
+
scope?: object;
|
|
143
|
+
});
|
|
144
|
+
get disposed(): boolean;
|
|
145
|
+
/** @internal */ get available(): boolean;
|
|
146
|
+
get diagnostics(): {
|
|
147
|
+
active: number;
|
|
148
|
+
};
|
|
149
|
+
get speed(): number;
|
|
150
|
+
set speed(value: number);
|
|
151
|
+
play(definition: TweenRecipe, options?: TweenPlayOptions): TweenPlayback;
|
|
152
|
+
/** @internal Eligibility snapshot before the Scene input/update phases. */
|
|
153
|
+
beginStep(): void;
|
|
154
|
+
advance(seconds: number): void;
|
|
155
|
+
/** @internal */ advanceCaptured(seconds: number): void;
|
|
156
|
+
/** @internal */ remove(p: TweenPlayback): void;
|
|
157
|
+
dispose(): void;
|
|
158
|
+
}
|
|
159
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type VisualSource } from "../graphics/components.js";
|
|
2
|
+
import type { ActionReader } from "../interaction/actions.js";
|
|
3
|
+
import { Actor } from "../scene/actor.js";
|
|
4
|
+
export interface CharacterOptions {
|
|
5
|
+
id?: string;
|
|
6
|
+
x?: number;
|
|
7
|
+
y?: number;
|
|
8
|
+
speed?: number;
|
|
9
|
+
size?: number;
|
|
10
|
+
color?: number;
|
|
11
|
+
movement?: ActionReader<"axis2d">;
|
|
12
|
+
source?: VisualSource;
|
|
13
|
+
}
|
|
14
|
+
export declare class CharacterActor extends Actor {
|
|
15
|
+
get x(): number;
|
|
16
|
+
set x(value: number);
|
|
17
|
+
get y(): number;
|
|
18
|
+
set y(value: number);
|
|
19
|
+
}
|
|
20
|
+
/** Composition preset; the simulation has no knowledge of characters. */
|
|
21
|
+
export declare function Character(options?: CharacterOptions): CharacterActor;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type EventType } from "../foundation/events.js";
|
|
2
|
+
import type { Actor } from "../scene/actor.js";
|
|
3
|
+
import { Component, type ComponentType } from "../scene/component.js";
|
|
4
|
+
export declare const CollisionShape: {
|
|
5
|
+
readonly Box: "box";
|
|
6
|
+
readonly Circle: "circle";
|
|
7
|
+
};
|
|
8
|
+
export type CollisionShape = (typeof CollisionShape)[keyof typeof CollisionShape];
|
|
9
|
+
import { CollisionResponse } from "./collision-policy.js";
|
|
10
|
+
export { CollisionResponse } from "./collision-policy.js";
|
|
11
|
+
type ShapeOptions = {
|
|
12
|
+
shape?: typeof CollisionShape.Box;
|
|
13
|
+
width?: number;
|
|
14
|
+
height?: number;
|
|
15
|
+
} | {
|
|
16
|
+
shape: typeof CollisionShape.Circle;
|
|
17
|
+
radius?: number;
|
|
18
|
+
};
|
|
19
|
+
export type ColliderOptions = ShapeOptions & {
|
|
20
|
+
response?: CollisionResponse;
|
|
21
|
+
offsetX?: number;
|
|
22
|
+
offsetY?: number;
|
|
23
|
+
layer?: number;
|
|
24
|
+
mask?: number;
|
|
25
|
+
};
|
|
26
|
+
export interface ContactGeometry {
|
|
27
|
+
/** Unit normal from self toward other at detection, before position correction. */
|
|
28
|
+
readonly normalX: number;
|
|
29
|
+
readonly normalY: number;
|
|
30
|
+
readonly depth: number;
|
|
31
|
+
readonly response: CollisionResponse;
|
|
32
|
+
readonly resolved: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface Contact extends ContactGeometry {
|
|
35
|
+
readonly self: Collider;
|
|
36
|
+
readonly other: Collider;
|
|
37
|
+
readonly selfActor: Actor;
|
|
38
|
+
readonly otherActor: Actor;
|
|
39
|
+
}
|
|
40
|
+
export declare const ContactEnter: EventType<Contact>;
|
|
41
|
+
export declare const ContactStay: EventType<Contact>;
|
|
42
|
+
export declare const ContactExit: EventType<Contact>;
|
|
43
|
+
/** Geometry and contact policy. CollisionBody separately controls position correction. */
|
|
44
|
+
export declare class Collider extends Component {
|
|
45
|
+
static readonly type: ComponentType<Collider>;
|
|
46
|
+
readonly type: ComponentType<Collider>;
|
|
47
|
+
readonly response: CollisionResponse;
|
|
48
|
+
readonly shape: CollisionShape;
|
|
49
|
+
readonly width: number;
|
|
50
|
+
readonly height: number;
|
|
51
|
+
readonly radius: number;
|
|
52
|
+
readonly offsetX: number;
|
|
53
|
+
readonly offsetY: number;
|
|
54
|
+
readonly layer: number;
|
|
55
|
+
readonly mask: number;
|
|
56
|
+
constructor(options?: ColliderOptions);
|
|
57
|
+
/** @internal */ notify<T>(type: EventType<T>, contact: T): void;
|
|
58
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Component, type ComponentType } from "../scene/component.js";
|
|
2
|
+
export declare const BodyType: {
|
|
3
|
+
readonly Static: "static";
|
|
4
|
+
readonly Dynamic: "dynamic";
|
|
5
|
+
};
|
|
6
|
+
export type BodyType = (typeof BodyType)[keyof typeof BodyType];
|
|
7
|
+
/** Position-correction participation, not velocity integration or a rigid body. */
|
|
8
|
+
export declare class CollisionBody extends Component {
|
|
9
|
+
static readonly type: ComponentType<CollisionBody>;
|
|
10
|
+
readonly type: ComponentType<CollisionBody>;
|
|
11
|
+
readonly motion: BodyType;
|
|
12
|
+
readonly mass: number;
|
|
13
|
+
constructor(options?: {
|
|
14
|
+
motion?: BodyType;
|
|
15
|
+
mass?: number;
|
|
16
|
+
});
|
|
17
|
+
get inverseMass(): number;
|
|
18
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ContactGeometry } from "./collider.js";
|
|
2
|
+
import type { Manifold } from "./collision-geometry.js";
|
|
3
|
+
import type { CollisionResponse } from "./collision-policy.js";
|
|
4
|
+
export type Mutable<T> = {
|
|
5
|
+
-readonly [K in keyof T]: T[K];
|
|
6
|
+
};
|
|
7
|
+
export interface ContactObservation {
|
|
8
|
+
seen: number;
|
|
9
|
+
readonly aContact: Mutable<ContactGeometry>;
|
|
10
|
+
readonly bContact?: Mutable<ContactGeometry>;
|
|
11
|
+
}
|
|
12
|
+
/** One observation path for both public payload families. */
|
|
13
|
+
export declare function observeContact(pair: ContactObservation, pass: number, manifold: Manifold, response: CollisionResponse, sign?: number): void;
|
|
14
|
+
export type ContactPhase = "enter" | "stay" | "exit";
|
|
15
|
+
export declare function contactPhase(entered: boolean, active: boolean): ContactPhase;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Transform } from "../graphics/components.js";
|
|
2
|
+
import type { Actor } from "../scene/actor.js";
|
|
3
|
+
import { type Collider } from "./collider.js";
|
|
4
|
+
export interface GeometryEntry {
|
|
5
|
+
readonly actor: Actor;
|
|
6
|
+
readonly collider: Collider;
|
|
7
|
+
readonly transform: Transform;
|
|
8
|
+
readonly geometry: Geometry;
|
|
9
|
+
}
|
|
10
|
+
/** Narrow phase needs shape data only, not Actor ownership or a Transform. */
|
|
11
|
+
export interface ManifoldEntry {
|
|
12
|
+
readonly collider: Pick<Collider, "shape">;
|
|
13
|
+
readonly geometry: Geometry;
|
|
14
|
+
}
|
|
15
|
+
export interface Manifold {
|
|
16
|
+
normalX: number;
|
|
17
|
+
normalY: number;
|
|
18
|
+
depth: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function createGeometry(): Geometry;
|
|
21
|
+
export interface Geometry {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
hx: number;
|
|
25
|
+
hy: number;
|
|
26
|
+
radius: number;
|
|
27
|
+
cos: number;
|
|
28
|
+
sin: number;
|
|
29
|
+
minX: number;
|
|
30
|
+
minY: number;
|
|
31
|
+
maxX: number;
|
|
32
|
+
maxY: number;
|
|
33
|
+
}
|
|
34
|
+
export declare function updateGeometry(entry: GeometryEntry): boolean;
|
|
35
|
+
/** Exact existing circle/OBB tests, extended to return a minimum translation normal. */
|
|
36
|
+
export declare function contactManifold(a: ManifoldEntry, b: ManifoldEntry, out: Manifold, tolerance?: number): boolean;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const CollisionResponse: {
|
|
2
|
+
readonly Trigger: "trigger";
|
|
3
|
+
readonly Solid: "solid";
|
|
4
|
+
};
|
|
5
|
+
export type CollisionResponse = (typeof CollisionResponse)[keyof typeof CollisionResponse];
|
|
6
|
+
export interface CollisionPolicy {
|
|
7
|
+
readonly response: CollisionResponse;
|
|
8
|
+
readonly layer: number;
|
|
9
|
+
readonly mask: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function collisionResponse(value: CollisionResponse): CollisionResponse;
|
|
12
|
+
export declare function collisionBits(value: number, name: string, allowZero: boolean): number;
|
|
13
|
+
export declare function allowsPair(a: CollisionPolicy, b: CollisionPolicy): boolean;
|
|
14
|
+
export declare function pairResponse(a: CollisionPolicy, b: CollisionPolicy): CollisionResponse;
|
|
15
|
+
export declare function samePolicy(a: CollisionPolicy | null, b: CollisionPolicy | null): boolean;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Transform } from "../graphics/components.js";
|
|
2
|
+
import type { Manifold } from "./collision-geometry.js";
|
|
3
|
+
/** Translate along the minimum separation axis, preserving tangential movement intent. */
|
|
4
|
+
export declare function correctPositions(a: Pick<Transform, "x" | "y">, b: Pick<Transform, "x" | "y">, contact: Manifold, ia: number, ib: number): boolean;
|