effect-motion 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/Camera.d.ts +186 -49
- package/dist/Camera.js +343 -76
- package/dist/Color.d.ts +101 -1
- package/dist/Color.js +101 -1
- package/dist/EffectMotionError.d.ts +17 -0
- package/dist/EffectMotionError.js +17 -0
- package/dist/Entity.d.ts +684 -30
- package/dist/Entity.js +281 -27
- package/dist/Font.d.ts +108 -0
- package/dist/Font.js +95 -0
- package/dist/Image.d.ts +71 -0
- package/dist/Image.js +50 -0
- package/dist/Instance.d.ts +73 -11
- package/dist/Instance.js +44 -11
- package/dist/Motion.d.ts +328 -53
- package/dist/Motion.js +278 -46
- package/dist/Physics.d.ts +154 -20
- package/dist/Physics.js +92 -11
- package/dist/Projection.d.ts +36 -132
- package/dist/Projection.js +33 -292
- package/dist/Resource.d.ts +26 -0
- package/dist/Resource.js +41 -0
- package/dist/Runner.d.ts +714 -349
- package/dist/Runner.js +197 -150
- package/dist/Scene.d.ts +603 -175
- package/dist/Scene.js +596 -112
- package/dist/Timing.d.ts +170 -13
- package/dist/Timing.js +124 -6
- package/dist/Tree.d.ts +39 -0
- package/dist/Tree.js +127 -0
- package/dist/index.d.ts +54 -5
- package/dist/index.js +56 -5
- package/dist/particles/Particle.d.ts +2 -2
- package/dist/particles/ParticleField.d.ts +44 -42
- package/dist/particles/ParticleField.js +8 -9
- package/dist/particles/constructors.d.ts +5 -6
- package/dist/particles/constructors.js +8 -3
- package/dist/particles/legacy.d.ts +58 -0
- package/dist/particles/legacy.js +46 -0
- package/dist/particles/simulate.js +11 -3
- package/dist/particles/step.js +14 -10
- package/dist/types.d.ts +5 -0
- package/dist/types.js +1 -0
- package/package.json +58 -60
- package/dist/CameraHelpers.d.ts +0 -70
- package/dist/CameraHelpers.js +0 -239
- package/dist/CanvasExporter.d.ts +0 -12
- package/dist/CanvasExporter.js +0 -40
- package/dist/Fonts.d.ts +0 -41
- package/dist/Fonts.js +0 -27
- package/dist/Images.d.ts +0 -33
- package/dist/Images.js +0 -24
- package/dist/PngExporter.d.ts +0 -6
- package/dist/PngExporter.js +0 -85
- package/dist/Renderer.d.ts +0 -118
- package/dist/Renderer.js +0 -508
- package/dist/Shapes.d.ts +0 -11
- package/dist/Shapes.js +0 -11
- package/dist/demo.d.ts +0 -3
- package/dist/demo.js +0 -71
- package/dist/render/dof.d.ts +0 -27
- package/dist/render/dof.js +0 -37
- package/dist/render/paint.d.ts +0 -30
- package/dist/render/paint.js +0 -36
- package/dist/render/shapes.d.ts +0 -42
- package/dist/render/shapes.js +0 -310
- package/dist/shapes/Circle.d.ts +0 -32
- package/dist/shapes/Circle.js +0 -9
- package/dist/shapes/Ellipse.d.ts +0 -35
- package/dist/shapes/Ellipse.js +0 -10
- package/dist/shapes/Group.d.ts +0 -126
- package/dist/shapes/Group.js +0 -89
- package/dist/shapes/Hud.d.ts +0 -38
- package/dist/shapes/Hud.js +0 -35
- package/dist/shapes/Image.d.ts +0 -45
- package/dist/shapes/Image.js +0 -28
- package/dist/shapes/Line.d.ts +0 -47
- package/dist/shapes/Line.js +0 -35
- package/dist/shapes/Path.d.ts +0 -107
- package/dist/shapes/Path.js +0 -32
- package/dist/shapes/Rect.d.ts +0 -51
- package/dist/shapes/Rect.js +0 -22
- package/dist/shapes/Shape2D.d.ts +0 -49
- package/dist/shapes/Shape2D.js +0 -52
- package/dist/shapes/Shapes.d.ts +0 -11
- package/dist/shapes/Shapes.js +0 -11
- package/dist/shapes/Square.d.ts +0 -32
- package/dist/shapes/Square.js +0 -11
- package/dist/shapes/Text.d.ts +0 -51
- package/dist/shapes/Text.js +0 -24
package/dist/Scene.d.ts
CHANGED
|
@@ -1,60 +1,211 @@
|
|
|
1
|
-
import { Context } from "effect";
|
|
2
1
|
import * as Cause from "effect/Cause";
|
|
3
2
|
import type * as Duration from "effect/Duration";
|
|
4
3
|
import * as Effect from "effect/Effect";
|
|
5
4
|
import * as Fiber from "effect/Fiber";
|
|
6
5
|
import type * as Schedule from "effect/Schedule";
|
|
7
|
-
import type * as Schema from "effect/Schema";
|
|
8
6
|
import type * as Scope from "effect/Scope";
|
|
9
7
|
import * as Stream from "effect/Stream";
|
|
10
|
-
import type * as Camera from "./Camera.js";
|
|
11
8
|
import type * as Color from "./Color.js";
|
|
12
|
-
import
|
|
9
|
+
import * as Entity from "./Entity.js";
|
|
13
10
|
import type * as Instance from "./Instance.js";
|
|
14
11
|
import * as Phaser from "./Phaser.js";
|
|
12
|
+
import type * as Projection from "./Projection.js";
|
|
13
|
+
import type * as Resource from "./Resource.js";
|
|
15
14
|
import * as Runner from "./Runner.js";
|
|
16
15
|
export declare const TypeId: "~motion/Scene";
|
|
16
|
+
/**
|
|
17
|
+
* A scene: an animation body plus the composition it plays in.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* Inert on its own — building one runs no animation and produces no frames.
|
|
21
|
+
* It is a description that {@link run}, {@link stream}, or {@link play}
|
|
22
|
+
* later executes, which is what lets the same scene be replayed, nested, or
|
|
23
|
+
* rendered at different settings without change.
|
|
24
|
+
*
|
|
25
|
+
* @typeParam E - How the scene can fail.
|
|
26
|
+
* @typeParam R - What it needs to run (fonts, images, and other resources).
|
|
27
|
+
*/
|
|
17
28
|
export interface Scene<E = never, R = never> {
|
|
18
29
|
readonly [TypeId]: typeof TypeId;
|
|
19
|
-
|
|
30
|
+
/**
|
|
31
|
+
* The scene body. Loader requirements are EXCLUDED here: frames are pure
|
|
32
|
+
* of resource bytes (the engine cannot measure text), so running a scene
|
|
33
|
+
* never needs a loader — only rendering its frames does (they re-surface
|
|
34
|
+
* on `Frame<Resources>` via `~resources`).
|
|
35
|
+
*/
|
|
36
|
+
readonly runner: Effect.Effect<void, E, Resource.ExcludeLoaders<R> | Scope.Scope>;
|
|
20
37
|
/**
|
|
21
38
|
* composition config, After Effects–style: what this comp IS. The
|
|
22
39
|
* runner inherits the ROOT scene's; a played scene keeps its own as
|
|
23
|
-
* its bounds (see {@link play}).
|
|
40
|
+
* its bounds (see {@link play}).
|
|
24
41
|
*/
|
|
25
42
|
readonly width: number;
|
|
26
43
|
readonly height: number;
|
|
27
44
|
readonly backgroundColor: Color.Color;
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
45
|
+
/**
|
|
46
|
+
* DISPLAY-ONLY name (a picker label, never an identifier) — set via the
|
|
47
|
+
* optional leading argument of {@link make}. Names may collide; unique
|
|
48
|
+
* identity belongs to whatever registers the scene (e.g. a studio.ts
|
|
49
|
+
* record key). Never read by the runtime: playback is identical with
|
|
50
|
+
* and without a name.
|
|
51
|
+
*/
|
|
52
|
+
readonly name?: string;
|
|
53
|
+
/** phantom: the loader members of R, carried to `Frame<Resources>` */
|
|
54
|
+
readonly "~resources": Resource.ExtractLoaders<R>;
|
|
32
55
|
}
|
|
33
|
-
export type AnyScene = Scene<
|
|
34
|
-
|
|
35
|
-
export
|
|
56
|
+
export type AnyScene = Scene<any, any>;
|
|
57
|
+
/** the loader requirements a scene's frames carry (what render will demand) */
|
|
58
|
+
export type Resources<S extends AnyScene> = S["~resources"];
|
|
59
|
+
/** the scene's failure channel */
|
|
60
|
+
export type Error<S extends AnyScene> = S extends Scene<infer E, any> ? E : never;
|
|
61
|
+
type GeneratorE<Eff> = [Eff] extends [never] ? never : [Eff] extends [Effect.Effect<infer _A, infer E, infer _R>] ? E : never;
|
|
62
|
+
type GeneratorR<Eff> = [Eff] extends [never] ? never : [Eff] extends [Effect.Effect<infer _A, infer _E, infer R>] ? R : never;
|
|
63
|
+
/**
|
|
64
|
+
* Declare a scene from a generator body.
|
|
65
|
+
*
|
|
66
|
+
* @remarks
|
|
67
|
+
* The generator is where a scene is written: `yield*` an
|
|
68
|
+
* {@link instantiate} to create something, `yield*` an animator to move it.
|
|
69
|
+
* Yielding is what makes time pass — statements between yields all happen on
|
|
70
|
+
* the same frame.
|
|
71
|
+
*
|
|
72
|
+
* The body does NOT run here. `make` captures it, so a scene can be
|
|
73
|
+
* declared once at module scope and run many times; each run re-executes
|
|
74
|
+
* the body from scratch with fresh entities.
|
|
75
|
+
*
|
|
76
|
+
* `meta` sets what the composition IS — its pixel dimensions and background.
|
|
77
|
+
* That is distinct from playback settings like frame rate and seed, which
|
|
78
|
+
* are chosen later at {@link run} / {@link stream}, because the same scene
|
|
79
|
+
* may legitimately be played back at different rates.
|
|
80
|
+
*
|
|
81
|
+
* An optional leading `name` is a display label for pickers and tooling
|
|
82
|
+
* only; it is never read during playback.
|
|
83
|
+
*
|
|
84
|
+
* @param f - The scene body.
|
|
85
|
+
* @param meta - Composition config: `width`, `height`, `backgroundColor`.
|
|
86
|
+
* @defaultValue `meta` — 1920×1080, transparent background
|
|
87
|
+
* @returns An inert {@link Scene}, ready to run, stream, or play.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* A named 500×300 scene on a dark background.
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const scene = Scene.make(
|
|
93
|
+
* "intro",
|
|
94
|
+
* function* () {
|
|
95
|
+
* const dot = yield* Scene.instantiate("Circle", { radius: 20 });
|
|
96
|
+
* yield* dot.pipe(Motion.moveTo({ x: 400 }, "1 second"));
|
|
97
|
+
* },
|
|
98
|
+
* { width: 500, height: 300, backgroundColor: Color.hex("#16161d") },
|
|
99
|
+
* );
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare const make: {
|
|
103
|
+
<const Eff extends Effect.Effect<any, any, any>, const AEff>(f: () => Generator<Eff, AEff, never>, meta?: Partial<Runner.CompConfig>): Scene<GeneratorE<Eff>, GeneratorR<Eff>>;
|
|
104
|
+
<const Eff extends Effect.Effect<any, any, any>, const AEff>(name: string, f: () => Generator<Eff, AEff, never>, meta?: Partial<Runner.CompConfig>): Scene<GeneratorE<Eff>, GeneratorR<Eff>>;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Create an entity and put it in the scene.
|
|
108
|
+
*
|
|
109
|
+
* @remarks
|
|
110
|
+
* `kind` selects the entity and, with it, the exact props allowed — asking
|
|
111
|
+
* for a `"Circle"` gets you `radius`, a `"Text"` gets `text` and
|
|
112
|
+
* `fontSize`. Everything is optional and defaulted, so `instantiate("Circle",
|
|
113
|
+
* {})` is a valid white circle at the origin.
|
|
114
|
+
*
|
|
115
|
+
* The entity appears immediately and stays for the rest of the scene. It is
|
|
116
|
+
* mounted under the ambient parent — the root, or the enclosing Group when
|
|
117
|
+
* created inside one.
|
|
118
|
+
*
|
|
119
|
+
* What you get back is a lightweight HANDLE, not the entity's data. It is
|
|
120
|
+
* what animators take, and it stays valid as the data changes underneath;
|
|
121
|
+
* to read the current state use {@link data}. Because the handle is itself
|
|
122
|
+
* pipeable, you can animate straight off the call without binding it first.
|
|
123
|
+
*
|
|
124
|
+
* Containers (`Group`, `Hud`) accept a `children` array that is deliberately
|
|
125
|
+
* permissive: a bare string becomes a Text, an existing handle is adopted,
|
|
126
|
+
* and an un-yielded `instantiate` is resolved for you.
|
|
127
|
+
*
|
|
128
|
+
* @param kind - Which entity: `"Circle"`, `"Rect"`, `"Text"`, `"Line"`,
|
|
129
|
+
* `"Path"`, `"Ellipse"`, `"Group"`, `"Hud"`, `"Image"`, or `"Camera"`.
|
|
130
|
+
* @param props - Initial field values; all optional.
|
|
131
|
+
* @returns A handle to the live entity.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* A shape, and a Group adopting mixed children.
|
|
135
|
+
* ```typescript
|
|
136
|
+
* const dot = yield* Scene.instantiate("Circle", {
|
|
137
|
+
* position: Entity.vec3({ x: 100, y: 50 }),
|
|
138
|
+
* radius: 20,
|
|
139
|
+
* fillColor: Color.hex("#7f5af0"),
|
|
140
|
+
* });
|
|
141
|
+
*
|
|
142
|
+
* const panel = yield* Scene.instantiate("Group", {
|
|
143
|
+
* children: [
|
|
144
|
+
* "a bare string becomes a Text",
|
|
145
|
+
* Scene.instantiate("Rect", { width: 200, height: 40 }),
|
|
146
|
+
* dot,
|
|
147
|
+
* ],
|
|
148
|
+
* });
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export declare const instantiate: <Tag extends Entity.EntityTag>(kind: Tag, props: Runner.InstantiateProps<Tag>) => Effect.Effect<Instance.Instance<Tag>, never, Runner.Runner>;
|
|
36
152
|
export declare const tick: Effect.Effect<void, never, Runner.Runner>;
|
|
37
153
|
/**
|
|
38
|
-
* Hold the scene for `duration
|
|
39
|
-
*
|
|
40
|
-
*
|
|
154
|
+
* Hold the scene still for `duration`.
|
|
155
|
+
*
|
|
156
|
+
* @remarks
|
|
157
|
+
* `Effect.sleep`'s sibling, but counted in FRAMES at the runner's frame
|
|
158
|
+
* rate rather than read from a clock. That distinction is load-bearing:
|
|
159
|
+
* a wall-clock sleep would produce a different number of frames on a slow
|
|
160
|
+
* machine, and scenes must be reproducible.
|
|
161
|
+
*
|
|
162
|
+
* A zero-length duration is a no-op — unlike an animator, which always
|
|
163
|
+
* consumes at least one frame.
|
|
164
|
+
*
|
|
165
|
+
* Use `Motion.wait` instead when the hold belongs inside an animator chain.
|
|
166
|
+
*
|
|
167
|
+
* @param duration - How long to hold, in scene time.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* yield* Scene.sleep("500 millis");
|
|
172
|
+
* ```
|
|
41
173
|
*/
|
|
42
174
|
export declare const sleep: (duration: Duration.Input) => Effect.Effect<void, never, Runner.Runner>;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
175
|
+
/**
|
|
176
|
+
* One instance as a frame carries it. The entity DEFINITION is gone: `data`
|
|
177
|
+
* is a member of the closed union, so `data._tag` is the identity and the
|
|
178
|
+
* renderer narrows on it instead of dispatching on an entity object.
|
|
179
|
+
*/
|
|
180
|
+
export interface FrameEntry {
|
|
181
|
+
data: Entity.Entity;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* One rendered moment: every entity's state at a single instant, plus the
|
|
185
|
+
* metadata needed to draw it.
|
|
186
|
+
*
|
|
187
|
+
* @remarks
|
|
188
|
+
* A frame is self-describing — it carries its own resolution, background,
|
|
189
|
+
* frame rate, and camera view, so a renderer needs nothing but the frame to
|
|
190
|
+
* produce a picture. That is what lets frames be serialized, cached, or sent
|
|
191
|
+
* to a different process.
|
|
192
|
+
*
|
|
193
|
+
* `instances` is keyed by instance id and holds plain data, not handles. The
|
|
194
|
+
* active camera is deliberately absent from it (it is view state, surfaced
|
|
195
|
+
* as `camera` instead), and `root` names the group everything hangs from,
|
|
196
|
+
* which is never itself drawn.
|
|
197
|
+
*
|
|
198
|
+
* @typeParam Resources - Fonts and images the renderer will need; frames
|
|
199
|
+
* carry the requirement, never the bytes.
|
|
200
|
+
*/
|
|
201
|
+
export interface Frame<out Resources = never> {
|
|
46
202
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
203
|
+
* phantom: the loader requirements the renderer will demand for this
|
|
204
|
+
* frame. Never a runtime value — an unused type parameter would be
|
|
205
|
+
* structurally erased, so it must anchor on an (always-absent) field.
|
|
50
206
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
export type EntriesFromEntities<Entities> = Entities extends Entity.AnyEntity ? {
|
|
54
|
-
[K in Entities as K["name"]]: FrameEntry<K>;
|
|
55
|
-
}[Entities["name"]] : never;
|
|
56
|
-
export interface Frame<Entities extends Entity.AnyEntity = Entity.AnyEntity> {
|
|
57
|
-
instances: Record<string, EntriesFromEntities<Entities>>;
|
|
207
|
+
readonly "~resources"?: Resources;
|
|
208
|
+
instances: Record<string, FrameEntry>;
|
|
58
209
|
/** id of the root group (conventionally "root"); never rendered itself */
|
|
59
210
|
root: string;
|
|
60
211
|
/** render metadata — frameRate from the runner settings, resolution and
|
|
@@ -63,10 +214,33 @@ export interface Frame<Entities extends Entity.AnyEntity = Entity.AnyEntity> {
|
|
|
63
214
|
width: number;
|
|
64
215
|
height: number;
|
|
65
216
|
backgroundColor: Color.Color;
|
|
66
|
-
/** the active camera's view;
|
|
67
|
-
camera:
|
|
217
|
+
/** the active camera's view; the resting view when unused */
|
|
218
|
+
camera: Projection.CameraView & Projection.PointOfInterest;
|
|
219
|
+
/**
|
|
220
|
+
* Mounted scenes (`Scene.play`), keyed by the id of the group they mount
|
|
221
|
+
* under. Each is a render-to-texture boundary: the renderer draws the
|
|
222
|
+
* subtree to its own target at these bounds, under an identity camera,
|
|
223
|
+
* and composites the result. An id absent here is a plain group.
|
|
224
|
+
*/
|
|
225
|
+
comps: Record<string, Runner.CompConfig>;
|
|
68
226
|
}
|
|
69
|
-
|
|
227
|
+
/**
|
|
228
|
+
* Advance a running scene by exactly one frame.
|
|
229
|
+
*
|
|
230
|
+
* @remarks
|
|
231
|
+
* Returns the frame that was produced, or `null` once the scene is over —
|
|
232
|
+
* which is the signal to stop pulling. Every concurrent branch advances
|
|
233
|
+
* together on each call, which is what keeps concurrency from affecting the
|
|
234
|
+
* frames a scene produces.
|
|
235
|
+
*
|
|
236
|
+
* A scene that runs past its `maxFrames` cap dies here with a message
|
|
237
|
+
* naming the limit, rather than looping forever — the guard against an
|
|
238
|
+
* accidental `Schedule.forever` with nothing to stop it.
|
|
239
|
+
*
|
|
240
|
+
* @param runningScene - The handle from {@link run}.
|
|
241
|
+
* @returns The next frame, or `null` when the scene has ended.
|
|
242
|
+
*/
|
|
243
|
+
export declare const step: <E, R>(runningScene: RunningScene<E, R>) => Effect.Effect<Frame<Resource.ExtractLoaders<R>> | null, E, never>;
|
|
70
244
|
export interface RunningScene<E, R> {
|
|
71
245
|
readonly runner: Runner.Runner["Service"];
|
|
72
246
|
readonly scene: Scene<E, R>;
|
|
@@ -75,11 +249,120 @@ export interface RunningScene<E, R> {
|
|
|
75
249
|
/** frames delivered so far — mutated by `step` for the maxFrames cap */
|
|
76
250
|
framesDelivered: number;
|
|
77
251
|
}
|
|
78
|
-
|
|
79
|
-
|
|
252
|
+
/**
|
|
253
|
+
* Start a scene and hand back a handle for advancing it manually.
|
|
254
|
+
*
|
|
255
|
+
* @remarks
|
|
256
|
+
* The low-level entry point, for drivers that need to own the frame loop —
|
|
257
|
+
* an exporter writing files, or a player synchronizing to its own clock.
|
|
258
|
+
* Starting a scene does not produce any frames; pair this with {@link step}
|
|
259
|
+
* to pull them one at a time.
|
|
260
|
+
*
|
|
261
|
+
* Most code wants {@link stream} instead, which wraps exactly this pairing
|
|
262
|
+
* in a stream.
|
|
263
|
+
*
|
|
264
|
+
* @param scene - The scene to start.
|
|
265
|
+
* @param settings - Playback settings.
|
|
266
|
+
* @returns A running-scene handle to pass to {@link step}.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const running = yield* Scene.run(scene, { frameRate: 30 });
|
|
271
|
+
* let frame = yield* Scene.step(running);
|
|
272
|
+
* while (frame !== null) {
|
|
273
|
+
* frame = yield* Scene.step(running);
|
|
274
|
+
* }
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
export declare const run: <E, R>(scene: Scene<E, R>, settings?: Partial<Runner.Settings>) => Effect.Effect<RunningScene<E, R>, never, Scope.Scope | Exclude<Exclude<Exclude<Exclude<Resource.ExcludeLoaders<R>, Scope.Scope>, never>, Phaser.Phaser>, Runner.Runner>>;
|
|
278
|
+
/**
|
|
279
|
+
* Play a scene and get its frames as a lazy stream — the usual way to
|
|
280
|
+
* consume one.
|
|
281
|
+
*
|
|
282
|
+
* @remarks
|
|
283
|
+
* Frames are produced on demand, so a player can pull at its own pace and a
|
|
284
|
+
* long scene never has to be materialized all at once. The stream ends when
|
|
285
|
+
* the scene does.
|
|
286
|
+
*
|
|
287
|
+
* `settings` is where playback choices live — `frameRate`, `seed`,
|
|
288
|
+
* `maxFrames` — as opposed to what the composition IS (its size and
|
|
289
|
+
* background), which was fixed at {@link make}. The same scene can therefore
|
|
290
|
+
* be streamed at 30fps for a preview and 60fps for a final render without
|
|
291
|
+
* being rewritten.
|
|
292
|
+
*
|
|
293
|
+
* Note the frame count depends on the frame rate: a one-second animation is
|
|
294
|
+
* 30 frames at 30fps and 60 at 60fps, plus a final resting frame.
|
|
295
|
+
*
|
|
296
|
+
* @param scene - The scene to play.
|
|
297
|
+
* @param settings - Playback settings.
|
|
298
|
+
* @defaultValue `frameRate` 60, `seed` `"effect-motion"`, `maxFrames` 36_000
|
|
299
|
+
* @returns A stream of frames.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* Collect every frame of a scene at 30fps.
|
|
303
|
+
* ```typescript
|
|
304
|
+
* const frames = yield* Scene.stream(scene, { frameRate: 30 }).pipe(
|
|
305
|
+
* Stream.runCollect,
|
|
306
|
+
* );
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
export declare const stream: <E = never, R = never>(scene: Scene<E, R>, settings?: Partial<Runner.Settings>) => Stream.Stream<Frame<Resource.ExtractLoaders<R>>, Exclude<E, Cause.Done<any>>, Exclude<Exclude<Exclude<Exclude<Exclude<Resource.ExcludeLoaders<R>, Scope.Scope>, never>, Phaser.Phaser>, Runner.Runner>, Scope.Scope>>;
|
|
80
310
|
type Updater<Data> = Data | ((data: Data) => Data);
|
|
81
|
-
|
|
82
|
-
|
|
311
|
+
/**
|
|
312
|
+
* Read an entity's current data.
|
|
313
|
+
*
|
|
314
|
+
* @remarks
|
|
315
|
+
* An {@link Instance} is only a handle, so this is how you get at the live
|
|
316
|
+
* values behind it — to branch on where something is, or to compute a target
|
|
317
|
+
* relative to its current state.
|
|
318
|
+
*
|
|
319
|
+
* The result is a snapshot for THIS frame, not a live view; read again on a
|
|
320
|
+
* later frame to see later values. The returned type is narrowed by the
|
|
321
|
+
* handle's kind, so a Circle's `radius` is available without casting.
|
|
322
|
+
*
|
|
323
|
+
* Reading a destroyed entity is a loud defect rather than a silent
|
|
324
|
+
* `undefined`.
|
|
325
|
+
*
|
|
326
|
+
* @param instance - Handle to read.
|
|
327
|
+
* @returns The entity's data as of this frame.
|
|
328
|
+
* @see {@link update} to write it.
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```typescript
|
|
332
|
+
* const { position, radius } = yield* Scene.data(dot);
|
|
333
|
+
* yield* dot.pipe(Motion.moveTo({ x: position.x + radius * 4 }, "1 second"));
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
export declare const data: <Tag extends Entity.EntityTag>(instance: Instance.Instance<Tag>) => Effect.Effect<Entity.EntityByTag<Tag>, never, Runner.Runner>;
|
|
337
|
+
/**
|
|
338
|
+
* Set an entity's data immediately, with no animation.
|
|
339
|
+
*
|
|
340
|
+
* @remarks
|
|
341
|
+
* A hard cut on the current frame — the counterpart to the animators, which
|
|
342
|
+
* interpolate. Use it to set something up before animating (jolt the camera,
|
|
343
|
+
* then spring it back), or to change a field no animator covers, like
|
|
344
|
+
* `text`, `visible`, or a Path's `commands`.
|
|
345
|
+
*
|
|
346
|
+
* Pass an object to replace the data, or a function to derive it from the
|
|
347
|
+
* current values — the function form is preferred, since it reads and writes
|
|
348
|
+
* atomically.
|
|
349
|
+
*
|
|
350
|
+
* Updating a destroyed entity is a no-op returning `false`, not an error.
|
|
351
|
+
*
|
|
352
|
+
* @param instance - Handle to update.
|
|
353
|
+
* @param props - New data, or `(current) => next`.
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* Retitle a label and jolt the camera, both on this frame.
|
|
357
|
+
* ```typescript
|
|
358
|
+
* yield* Scene.update(label, (d) => ({ ...d, text: "done" }));
|
|
359
|
+
* yield* Scene.update(camera, (d) => ({
|
|
360
|
+
* ...d,
|
|
361
|
+
* position: Entity.vec3({ ...d.position, x: 22 }),
|
|
362
|
+
* }));
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
export declare const update: <Tag extends Entity.EntityTag>(instance: Instance.Instance<Tag>, props: Updater<Entity.EntityByTag<Tag>>) => Effect.Effect<void | false, never, Runner.Runner>;
|
|
83
366
|
/**
|
|
84
367
|
* Move `child` under `parent`, detaching it from its current parent first
|
|
85
368
|
* (so it is never double-referenced). Instances are born mounted under the
|
|
@@ -97,80 +380,34 @@ export declare const settings: () => Effect.Effect<{
|
|
|
97
380
|
/** the movie's composition config — the ROOT scene's width/height/background */
|
|
98
381
|
export declare const comp: () => Effect.Effect<Runner.CompConfig, never, Runner.Runner>;
|
|
99
382
|
/**
|
|
100
|
-
* The active camera
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* =
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
383
|
+
* The active camera, as an ordinary animatable instance.
|
|
384
|
+
*
|
|
385
|
+
* @remarks
|
|
386
|
+
* There is always a camera — a resting one is present from the first frame,
|
|
387
|
+
* placed so that content at `z = 0` renders exactly as flat 2D. A scene that
|
|
388
|
+
* never touches the camera looks like a plain 2D scene, and reaching for
|
|
389
|
+
* `Scene.camera` is how you opt into depth.
|
|
390
|
+
*
|
|
391
|
+
* It is a normal instance, so every animator drives it with no special
|
|
392
|
+
* vocabulary: `moveTo` flies it (including along `z` to push in or pull
|
|
393
|
+
* back), `tweenTo` on `focalLength` changes the lens, springs and forks work
|
|
394
|
+
* as they do anywhere. `Camera` helpers add aiming on top.
|
|
395
|
+
*
|
|
396
|
+
* The camera is view state and is never itself drawn.
|
|
397
|
+
*
|
|
398
|
+
* @returns A handle to the active camera.
|
|
399
|
+
* @see {@link setCamera} to swap in a different one.
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* Push the camera in, revealing depth in the scene.
|
|
403
|
+
* ```typescript
|
|
404
|
+
* const camera = yield* Scene.camera;
|
|
405
|
+
* yield* camera.pipe(Motion.moveTo({ z: -300 }, "1200 millis", "easeInOutCubic"));
|
|
406
|
+
* ```
|
|
109
407
|
*/
|
|
110
|
-
export declare const camera: Effect.Effect<Instance.Instance<"Camera",
|
|
111
|
-
x: Schema.withConstructorDefault<Schema.Number>;
|
|
112
|
-
y: Schema.withConstructorDefault<Schema.Number>;
|
|
113
|
-
z: Schema.withConstructorDefault<Schema.Number>;
|
|
114
|
-
rotX: Schema.withConstructorDefault<Schema.Number>;
|
|
115
|
-
rotY: Schema.withConstructorDefault<Schema.Number>;
|
|
116
|
-
rotZ: Schema.withConstructorDefault<Schema.Number>;
|
|
117
|
-
focalLength: Schema.withConstructorDefault<Schema.Number>;
|
|
118
|
-
focusDistance: Schema.withConstructorDefault<Schema.Number>;
|
|
119
|
-
aperture: Schema.withConstructorDefault<Schema.Number>;
|
|
120
|
-
poiX: Schema.optionalKey<Schema.Number>;
|
|
121
|
-
poiY: Schema.optionalKey<Schema.Number>;
|
|
122
|
-
poiZ: Schema.optionalKey<Schema.Number>;
|
|
123
|
-
}>, {
|
|
124
|
-
readonly "~position": {
|
|
125
|
-
get: (data: {
|
|
126
|
-
readonly x: number;
|
|
127
|
-
readonly y: number;
|
|
128
|
-
readonly z: number;
|
|
129
|
-
readonly rotX: number;
|
|
130
|
-
readonly rotY: number;
|
|
131
|
-
readonly rotZ: number;
|
|
132
|
-
readonly focalLength: number;
|
|
133
|
-
readonly focusDistance: number;
|
|
134
|
-
readonly aperture: number;
|
|
135
|
-
readonly poiX?: number;
|
|
136
|
-
readonly poiY?: number;
|
|
137
|
-
readonly poiZ?: number;
|
|
138
|
-
}) => {
|
|
139
|
-
x: number;
|
|
140
|
-
y: number;
|
|
141
|
-
z: number;
|
|
142
|
-
};
|
|
143
|
-
set: (data: {
|
|
144
|
-
readonly x: number;
|
|
145
|
-
readonly y: number;
|
|
146
|
-
readonly z: number;
|
|
147
|
-
readonly rotX: number;
|
|
148
|
-
readonly rotY: number;
|
|
149
|
-
readonly rotZ: number;
|
|
150
|
-
readonly focalLength: number;
|
|
151
|
-
readonly focusDistance: number;
|
|
152
|
-
readonly aperture: number;
|
|
153
|
-
readonly poiX?: number;
|
|
154
|
-
readonly poiY?: number;
|
|
155
|
-
readonly poiZ?: number;
|
|
156
|
-
}, value: Entity.Position) => {
|
|
157
|
-
readonly x: number;
|
|
158
|
-
readonly y: number;
|
|
159
|
-
readonly z: number;
|
|
160
|
-
readonly rotX: number;
|
|
161
|
-
readonly rotY: number;
|
|
162
|
-
readonly rotZ: number;
|
|
163
|
-
readonly focalLength: number;
|
|
164
|
-
readonly focusDistance: number;
|
|
165
|
-
readonly aperture: number;
|
|
166
|
-
readonly poiX?: number;
|
|
167
|
-
readonly poiY?: number;
|
|
168
|
-
readonly poiZ?: number;
|
|
169
|
-
};
|
|
170
|
-
};
|
|
171
|
-
}>, never, Runner.Runner>;
|
|
408
|
+
export declare const camera: Effect.Effect<Instance.Instance<"Camera">, never, Runner.Runner>;
|
|
172
409
|
/** Swap the active camera to `instance`; its live data becomes the view. */
|
|
173
|
-
export declare const setCamera: (instance: Instance.Instance) => Effect.Effect<void, never, Runner.Runner>;
|
|
410
|
+
export declare const setCamera: (instance: Instance.Instance<"Camera">) => Effect.Effect<void, never, Runner.Runner>;
|
|
174
411
|
/**
|
|
175
412
|
* Handle to a branch of animation (a fork, background, or played scene).
|
|
176
413
|
* `finished` resolves at the branch's SEMANTIC end — `Scene.finish` or
|
|
@@ -184,44 +421,150 @@ export interface BranchHandle<A = unknown, E = never> {
|
|
|
184
421
|
readonly fiber: Fiber.Fiber<A, E>;
|
|
185
422
|
}
|
|
186
423
|
/**
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
424
|
+
* Declare the current branch semantically over, while its code keeps
|
|
425
|
+
* running.
|
|
426
|
+
*
|
|
427
|
+
* @remarks
|
|
428
|
+
* Separates "this is done as far as everyone else is concerned" from "this
|
|
429
|
+
* fiber has stopped". Anyone awaiting the branch's `finished` proceeds
|
|
430
|
+
* immediately, and the branch stops holding the scene open — but code after
|
|
431
|
+
* `finish` keeps running as a TAIL, bounded by the parent exactly like a
|
|
432
|
+
* {@link background}.
|
|
433
|
+
*
|
|
434
|
+
* The use is a beat that should hand off early: an entrance whose successor
|
|
435
|
+
* starts as soon as the element has landed, while a slow ring-out continues
|
|
436
|
+
* underneath. Without `finish`, the successor would wait for the tail.
|
|
437
|
+
*
|
|
438
|
+
* Idempotent, and completion implies finish. Note that a failure in the tail
|
|
439
|
+
* is NOT reported — by then nothing is listening.
|
|
440
|
+
*
|
|
441
|
+
* Calling it outside a running scene is a loud defect.
|
|
442
|
+
*
|
|
443
|
+
* @example
|
|
444
|
+
* Hand off after the landing; the wobble plays on borrowed time.
|
|
445
|
+
* ```typescript
|
|
446
|
+
* yield* Scene.fork(
|
|
447
|
+
* Effect.gen(function* () {
|
|
448
|
+
* yield* badge.pipe(Motion.moveTo({ y: 100 }, "400 millis"));
|
|
449
|
+
* yield* Scene.finish;
|
|
450
|
+
* yield* badge.pipe(Physics.springTo({ y: 96 }, "bounce"));
|
|
451
|
+
* }),
|
|
452
|
+
* );
|
|
453
|
+
* ```
|
|
194
454
|
*/
|
|
195
455
|
export declare const finish: Effect.Effect<undefined, never, never>;
|
|
196
456
|
/**
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
* immediately
|
|
457
|
+
* Play an animation again and again, on a schedule.
|
|
458
|
+
*
|
|
459
|
+
* @remarks
|
|
460
|
+
* `Effect.repeat`'s sibling, paced by FRAMES rather than the wall clock —
|
|
461
|
+
* which is what keeps a looping scene deterministic.
|
|
462
|
+
*
|
|
463
|
+
* The first run happens immediately, and the schedule paces the gaps AFTER
|
|
464
|
+
* each run. So `Schedule.spaced("400 millis")` means "run, rest 400ms, run
|
|
465
|
+
* again", and the loop count comes from the schedule: `Schedule.forever`
|
|
466
|
+
* for ambient motion (usually inside {@link background}), or
|
|
467
|
+
* `Schedule.upTo({ times: 2 })` for a bounded three-run sequence.
|
|
468
|
+
*
|
|
469
|
+
* A failing run fails immediately, without consulting the schedule again.
|
|
470
|
+
*
|
|
471
|
+
* @param effect - The animation to repeat.
|
|
472
|
+
* @param schedule - How often, and how many times.
|
|
473
|
+
* @returns The schedule's final output.
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* Three round-trips, resting 400ms between them.
|
|
477
|
+
* ```typescript
|
|
478
|
+
* yield* Scene.repeat(
|
|
479
|
+
* ball.pipe(
|
|
480
|
+
* Motion.moveTo({ x: 430 }, "600 millis", "easeInOutCubic"),
|
|
481
|
+
* Motion.moveTo({ x: 70 }, "600 millis", "easeInOutCubic"),
|
|
482
|
+
* ),
|
|
483
|
+
* Schedule.spaced("400 millis").pipe(Schedule.upTo({ times: 2 })),
|
|
484
|
+
* );
|
|
485
|
+
* ```
|
|
204
486
|
*/
|
|
205
487
|
export declare const repeat: <A, E, R, Output, ScheduleE, ScheduleR>(effect: Effect.Effect<A, E, R>, schedule: Schedule.Schedule<Output, A, ScheduleE, ScheduleR>) => Effect.Effect<Output, E | ScheduleE, R | ScheduleR | Runner.Runner>;
|
|
206
488
|
/**
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
489
|
+
* Start an animation alongside the rest of the scene and continue
|
|
490
|
+
* immediately, without waiting for it.
|
|
491
|
+
*
|
|
492
|
+
* @remarks
|
|
493
|
+
* Where {@link all} blocks until its branches finish, `fork` returns at
|
|
494
|
+
* once — so the scene body carries on while the forked animation plays.
|
|
495
|
+
* That is what lets independent timelines overlap, and what makes spawning
|
|
496
|
+
* work in a loop possible.
|
|
497
|
+
*
|
|
498
|
+
* Note this INVERTS Effect's own `fork`: the scene's end waits for forked
|
|
499
|
+
* work. A body that returns while forks are still animating keeps producing
|
|
500
|
+
* frames until the last one finishes, so a scene consisting only of a fork
|
|
501
|
+
* still plays in full. For work that should instead be cut off when the
|
|
502
|
+
* scene ends, use {@link background}.
|
|
503
|
+
*
|
|
504
|
+
* The returned handle carries `finished` — yield it to wait for this branch
|
|
505
|
+
* specifically — and `fiber`, to interrupt it early.
|
|
506
|
+
*
|
|
507
|
+
* @param effect - The animation to run alongside.
|
|
508
|
+
* @returns A handle with `finished` and `fiber`.
|
|
509
|
+
* @see {@link background} for work bounded by the scene's end.
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* Spawn overlapping dots; the scene lives until the last one has faded.
|
|
513
|
+
* ```typescript
|
|
514
|
+
* yield* Scene.repeat(
|
|
515
|
+
* Scene.fork(
|
|
516
|
+
* Effect.gen(function* () {
|
|
517
|
+
* const dot = yield* Scene.instantiate("Circle", { radius: 8 });
|
|
518
|
+
* yield* dot.pipe(
|
|
519
|
+
* Motion.moveTo({ x: 440 }, "1200 millis"),
|
|
520
|
+
* Motion.fadeTo(0, "300 millis"),
|
|
521
|
+
* );
|
|
522
|
+
* }),
|
|
523
|
+
* ),
|
|
524
|
+
* Schedule.fixed("200 millis").pipe(Schedule.upTo({ times: 5 })),
|
|
525
|
+
* );
|
|
526
|
+
* ```
|
|
217
527
|
*/
|
|
218
528
|
export declare const fork: <A, E = never, R = never>(effect: Effect.Effect<A, E, R>) => Effect.Effect<BranchHandle<A, E>, never, Runner.Runner | Exclude<Exclude<R, never>, Phaser.Phaser>>;
|
|
219
529
|
/**
|
|
220
|
-
* Like {@link fork}, but the
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
530
|
+
* Like {@link fork}, but the animation is CUT OFF at scene end rather than
|
|
531
|
+
* awaited.
|
|
532
|
+
*
|
|
533
|
+
* @remarks
|
|
534
|
+
* For ambient motion that should play for as long as the scene lasts
|
|
535
|
+
* without deciding how long that is — a pulsing indicator, a drifting
|
|
536
|
+
* backdrop, anything paired with `Schedule.forever`. A background never
|
|
537
|
+
* holds the scene open, so the scene's real content governs its length and
|
|
538
|
+
* the ambient loop simply stops when everything else is done.
|
|
539
|
+
*
|
|
540
|
+
* "Scene end" includes the fork drain: backgrounds keep animating while
|
|
541
|
+
* awaited forks finish, and are stopped only after the last one.
|
|
542
|
+
*
|
|
543
|
+
* Because backgrounds do not keep a scene alive, a body that spawns only
|
|
544
|
+
* backgrounds ends immediately and produces NO frames — the background is
|
|
545
|
+
* not content, so there is nothing to give the scene a length. Pair one
|
|
546
|
+
* with something that does define the length, whether a real animation or
|
|
547
|
+
* an explicit {@link sleep}, or the ambient motion never gets a frame to
|
|
548
|
+
* play on.
|
|
549
|
+
*
|
|
550
|
+
* @param effect - The ambient animation.
|
|
551
|
+
* @returns A handle with `finished` and `fiber`.
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* A pulse that runs the whole scene, with the scene's length set by the
|
|
555
|
+
* animation after it.
|
|
556
|
+
* ```typescript
|
|
557
|
+
* yield* Scene.background(
|
|
558
|
+
* Scene.repeat(
|
|
559
|
+
* pulse.pipe(
|
|
560
|
+
* Motion.tweenTo({ radius: 24 }, "400 millis"),
|
|
561
|
+
* Motion.tweenTo({ radius: 10 }, "400 millis"),
|
|
562
|
+
* ),
|
|
563
|
+
* Schedule.forever,
|
|
564
|
+
* ),
|
|
565
|
+
* );
|
|
566
|
+
* yield* title.pipe(Motion.moveTo({ y: 100 }, "2 seconds"));
|
|
567
|
+
* ```
|
|
225
568
|
*/
|
|
226
569
|
export declare const background: <A, E = never, R = never>(effect: Effect.Effect<A, E, R>) => Effect.Effect<BranchHandle<A, E>, never, Runner.Runner | Exclude<Exclude<R, never>, Phaser.Phaser>>;
|
|
227
570
|
export interface PlayOptions {
|
|
@@ -231,60 +574,145 @@ export interface PlayOptions {
|
|
|
231
574
|
readonly seed?: Runner.Seed;
|
|
232
575
|
}
|
|
233
576
|
/**
|
|
234
|
-
* A played scene's branch
|
|
235
|
-
*
|
|
236
|
-
*
|
|
577
|
+
* A played scene's handle: its branch, plus the group it is mounted under.
|
|
578
|
+
*
|
|
579
|
+
* @remarks
|
|
580
|
+
* `group` is what makes a nested scene manipulable as ONE object — move,
|
|
581
|
+
* fade, or scale it and the entire child scene follows, its bounds included.
|
|
237
582
|
*/
|
|
238
583
|
export interface PlayHandle<A = void, E = never> extends BranchHandle<A, E> {
|
|
239
584
|
readonly group: Runner.GroupInstance;
|
|
240
585
|
}
|
|
241
586
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
587
|
+
* Nest a whole scene inside the current one — the precomp.
|
|
588
|
+
*
|
|
589
|
+
* @remarks
|
|
590
|
+
* The door to composing scenes rather than writing one flat timeline. A
|
|
591
|
+
* played scene is authored and tested independently, then dropped into a
|
|
592
|
+
* larger one as a unit: an intro built alone becomes the first beat of a
|
|
593
|
+
* longer piece without edits.
|
|
594
|
+
*
|
|
595
|
+
* The child mounts under an implicit group carrying its OWN bounds. Content
|
|
596
|
+
* clips to them, a non-transparent background paints within them, and the
|
|
597
|
+
* group is placed so those bounds sit centered in the enclosing composition
|
|
598
|
+
* — so a child smaller or larger than its parent still lands sensibly. The
|
|
599
|
+
* handle's `group` is that mount point: move or fade it to transform the
|
|
600
|
+
* entire nested scene as one object.
|
|
601
|
+
*
|
|
602
|
+
* The child shares the movie's frame clock but gets a FRESH seeded random
|
|
603
|
+
* stream, so a nested scene animates exactly as it did standalone under the
|
|
604
|
+
* same seed — nesting never perturbs a child's randomness.
|
|
605
|
+
*
|
|
606
|
+
* Awaited like a {@link fork}: yield `handle.finished` to play children in
|
|
607
|
+
* sequence, or skip the await to run them concurrently.
|
|
608
|
+
*
|
|
609
|
+
* @param scene - The scene to nest.
|
|
610
|
+
* @param options - `parent` to mount elsewhere, `seed` to vary this
|
|
611
|
+
* evaluation.
|
|
612
|
+
* @returns A handle with `finished`, `fiber`, and the mount `group`.
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* Play one scene, then another, and fade the second out as a whole.
|
|
616
|
+
* ```typescript
|
|
617
|
+
* const intro = yield* Scene.play(introScene);
|
|
618
|
+
* yield* intro.finished;
|
|
619
|
+
*
|
|
620
|
+
* const outro = yield* Scene.play(outroScene);
|
|
621
|
+
* yield* outro.group.pipe(Motion.fadeTo(0, "500 millis"));
|
|
622
|
+
* ```
|
|
255
623
|
*/
|
|
256
624
|
export declare const play: <E, R>(scene: Scene<E, R>, options?: PlayOptions) => Effect.Effect<PlayHandle<void, E>, never, Runner.Runner | Exclude<R, Scope.Scope>>;
|
|
257
625
|
/**
|
|
258
|
-
* Run
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
626
|
+
* Run animations simultaneously, and resolve when the last one finishes.
|
|
627
|
+
*
|
|
628
|
+
* @remarks
|
|
629
|
+
* The everyday way to make things move at once. Every branch advances
|
|
630
|
+
* exactly one frame per tick in lockstep, so two one-second animations run
|
|
631
|
+
* as one second of frames — not two.
|
|
632
|
+
*
|
|
633
|
+
* Branches need not be the same length; `all` waits for the slowest. This
|
|
634
|
+
* is also the idiom for synchronizing springs, whose durations are emergent
|
|
635
|
+
* and unknown up front.
|
|
636
|
+
*
|
|
637
|
+
* There is deliberately no schedule parameter: pacing a list one-at-a-time
|
|
638
|
+
* is {@link chain}, and overlapping starts is {@link stagger}.
|
|
639
|
+
*
|
|
640
|
+
* @param effects - The animations to run together.
|
|
641
|
+
*
|
|
642
|
+
* @example
|
|
643
|
+
* A dot slides while the camera pushes in — one second of frames total.
|
|
644
|
+
* ```typescript
|
|
645
|
+
* yield* Scene.all([
|
|
646
|
+
* dot.pipe(Motion.moveTo({ x: 400 }, "1 second")),
|
|
647
|
+
* camera.pipe(Motion.moveTo({ z: -300 }, "1 second")),
|
|
648
|
+
* ]);
|
|
649
|
+
* ```
|
|
262
650
|
*/
|
|
263
651
|
export declare const all: <Eff extends Effect.Effect<any, any, any>>(effects: Iterable<Eff>) => Effect.Effect<void, Eff extends Effect.Effect<any, infer E, any> ? E : never, Runner.Runner | Exclude<Eff extends Effect.Effect<any, any, infer R> ? R : never, Phaser.Phaser>>;
|
|
264
652
|
/**
|
|
265
|
-
* Run
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
653
|
+
* Run animations one at a time, in order, optionally resting between them.
|
|
654
|
+
*
|
|
655
|
+
* @remarks
|
|
656
|
+
* Items NEVER overlap — each begins only after the previous one has fully
|
|
657
|
+
* finished. That guarantee is the difference between this and
|
|
658
|
+
* {@link stagger}, and it holds no matter what schedule you pass.
|
|
659
|
+
*
|
|
660
|
+
* Without a schedule this is plain sequencing, equivalent to yielding each
|
|
661
|
+
* item in turn but composable as a list. With one, the schedule paces the
|
|
662
|
+
* GAPS after each item: `Schedule.spaced("400 millis")` rests 400ms between
|
|
663
|
+
* items, while `Schedule.fixed` targets a steady start-to-start cadence.
|
|
664
|
+
*
|
|
665
|
+
* The schedule also decides how many items run: when it ends, the remaining
|
|
666
|
+
* items are skipped. `Schedule.recurs(2)` therefore plays three items — the
|
|
667
|
+
* first, plus two more the schedule released.
|
|
668
|
+
*
|
|
669
|
+
* @param effects - The animations, in order.
|
|
670
|
+
* @param schedule - Optional pacing for the gaps between them.
|
|
671
|
+
* @returns `{ completed }` — how many items actually ran.
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* Three shapes flashing in turn, resting 400ms between each.
|
|
675
|
+
* ```typescript
|
|
676
|
+
* const { completed } = yield* Scene.chain(
|
|
677
|
+
* [a, b, c].map((shape) => shape.pipe(Motion.fadeTo(1, "300 millis"))),
|
|
678
|
+
* Schedule.spaced("400 millis"),
|
|
679
|
+
* );
|
|
680
|
+
* ```
|
|
275
681
|
*/
|
|
276
682
|
export declare const chain: <Eff extends Effect.Effect<any, any, any>, ScheduleE = never, ScheduleR = never>(effects: Iterable<Eff>, schedule?: Schedule.Schedule<unknown, Eff extends Effect.Effect<infer A, any, any> ? A : never, ScheduleE, ScheduleR>) => Effect.Effect<{
|
|
277
683
|
completed: number;
|
|
278
684
|
}, (Eff extends Effect.Effect<any, infer E, any> ? E : never) | ScheduleE, (Eff extends Effect.Effect<any, any, infer R> ? R : never) | Runner.Runner | ScheduleR>;
|
|
279
685
|
/**
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
686
|
+
* Start animations one after another WITHOUT waiting for each to finish —
|
|
687
|
+
* the cascade.
|
|
688
|
+
*
|
|
689
|
+
* @remarks
|
|
690
|
+
* The first starts immediately and each next one on the schedule's next
|
|
691
|
+
* emission, so earlier items are still running when later ones begin. That
|
|
692
|
+
* overlap is the entire point, and the difference from {@link chain}: use
|
|
693
|
+
* `stagger` for a ripple across many elements, `chain` when items must not
|
|
694
|
+
* coincide.
|
|
695
|
+
*
|
|
696
|
+
* The schedule paces the STARTS here, not the gaps. Resolution waits for
|
|
697
|
+
* every released animation to finish, not merely for the last one to be
|
|
698
|
+
* released — so the whole cascade is complete when this returns.
|
|
699
|
+
*
|
|
700
|
+
* When the schedule ends before the list does, the remaining effects are
|
|
701
|
+
* skipped.
|
|
702
|
+
*
|
|
703
|
+
* @param effects - The animations to release in order.
|
|
704
|
+
* @param schedule - When to release each subsequent one.
|
|
705
|
+
* @returns `{ released }` — how many actually started.
|
|
706
|
+
*
|
|
707
|
+
* @example
|
|
708
|
+
* A row of bars rising in a ripple, each starting 80ms after the last while
|
|
709
|
+
* the earlier ones keep going.
|
|
710
|
+
* ```typescript
|
|
711
|
+
* yield* Scene.stagger(
|
|
712
|
+
* bars.map((bar) => bar.pipe(Motion.moveTo({ y: 40 }, "600 millis"))),
|
|
713
|
+
* Schedule.spaced("80 millis"),
|
|
714
|
+
* );
|
|
715
|
+
* ```
|
|
288
716
|
*/
|
|
289
717
|
export declare const stagger: <Eff extends Effect.Effect<any, any, any>, ScheduleE = never, ScheduleR = never>(effects: Iterable<Eff>, schedule: Schedule.Schedule<unknown, void, ScheduleE, ScheduleR>) => Effect.Effect<{
|
|
290
718
|
released: number;
|