@glissade/core 0.18.0-pre.2 → 0.18.0-pre.3
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/dist/clips.d.ts +51 -8
- package/dist/clips.js +82 -4
- package/package.json +1 -1
package/dist/clips.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as ValueTypeId, Y as EaseSpec, r as Track, t as Key } from "./track.js";
|
|
1
|
+
import { D as Vec2, T as ValueTypeId, Y as EaseSpec, r as Track, t as Key } from "./track.js";
|
|
2
2
|
import { r as TweenTarget } from "./targetRef.js";
|
|
3
3
|
|
|
4
4
|
//#region src/clip.d.ts
|
|
@@ -182,20 +182,63 @@ declare function morph(from: Box, to: Box, targets: MorphTargets, opts: MorphOpt
|
|
|
182
182
|
declare class PresenceError extends Error {
|
|
183
183
|
constructor(message: string);
|
|
184
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* An inline ENTER/EXIT literal (0.18 sugar): a terse alternative to hand-building
|
|
187
|
+
* a `clip({channels})`. `transitionToClip` compiles it to the SAME `Clip` an author
|
|
188
|
+
* would write by hand, so presence() then runs UNCHANGED on the result — the inline
|
|
189
|
+
* spelling is byte-INDISTINGUISHABLE from the hand-authored clip path.
|
|
190
|
+
*
|
|
191
|
+
* Conventions mirror clipStdlib (`slideIn`/`popIn`): a scalar `offset` slides that
|
|
192
|
+
* magnitude in along `edge` (default 'bottom' = slide up from below); a scalar
|
|
193
|
+
* `scale` broadcasts to a Vec2; OMITTING `opacity` emits NO opacity channel so
|
|
194
|
+
* presence()'s synthesized rise/fall takes over (matching the Clip path exactly).
|
|
195
|
+
*/
|
|
196
|
+
interface PresenceTransition {
|
|
197
|
+
/** Opacity endpoints [from,to]. OMIT to rely on presence()'s synthesized rise/fall. */
|
|
198
|
+
opacity?: [number, number];
|
|
199
|
+
/**
|
|
200
|
+
* Slide displacement. A scalar slides that magnitude along `edge`; a single Vec2
|
|
201
|
+
* is the displaced point (animates to/from [0,0]); a [Vec2,Vec2] is explicit
|
|
202
|
+
* endpoints. Omit for no position channel.
|
|
203
|
+
*/
|
|
204
|
+
offset?: number | Vec2 | [Vec2, Vec2];
|
|
205
|
+
/** Slide edge for a scalar `offset` (clipStdlib convention). Default 'bottom'. */
|
|
206
|
+
edge?: SlideEdge;
|
|
207
|
+
/** Scale endpoints. A scalar pair broadcasts each value to a Vec2 (popIn convention). */
|
|
208
|
+
scale?: [number, number] | [Vec2, Vec2];
|
|
209
|
+
/** Transition length in seconds. Default = the presence DEFAULT_FADE (0.3). */
|
|
210
|
+
dur?: number;
|
|
211
|
+
/** Arriving ease of every channel's last segment. */
|
|
212
|
+
ease?: EaseSpec;
|
|
213
|
+
}
|
|
185
214
|
interface PresenceOpts {
|
|
186
215
|
/** Wall-clock second the node ENTERS (becomes visible). */
|
|
187
|
-
show
|
|
216
|
+
show?: number;
|
|
188
217
|
/** Wall-clock second the node has fully EXITED (the exit LANDS here). */
|
|
189
|
-
hide
|
|
190
|
-
/**
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
|
|
218
|
+
hide?: number;
|
|
219
|
+
/** Alias for `{ show: window[0], hide: window[1] }`. */
|
|
220
|
+
window?: [number, number];
|
|
221
|
+
/** Entrance clip, or an inline transition literal (default = a plain opacity fade-in 0→1, ~0.3s). */
|
|
222
|
+
enter?: Clip | PresenceTransition;
|
|
223
|
+
/** Exit clip, or an inline transition literal (default = a plain opacity fade-out 1→0, ~0.3s). Back-timed to land on `hide`. */
|
|
224
|
+
exit?: Clip | PresenceTransition;
|
|
194
225
|
/** Forwarded to `enter.apply` (speed / per-channel overrides). */
|
|
195
226
|
enterOpts?: ApplyOpts;
|
|
196
227
|
/** Forwarded to `exit.apply` (speed / per-channel overrides). */
|
|
197
228
|
exitOpts?: ApplyOpts;
|
|
198
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Compile an inline `PresenceTransition` literal into the SAME `Clip` an author
|
|
232
|
+
* would hand-write — an opacity channel (only when `opacity` is given), a position
|
|
233
|
+
* channel from `offset`+`edge` (slideIn convention), and a scale channel (scalar
|
|
234
|
+
* broadcast to Vec2, popIn convention). presence() then runs UNCHANGED on it.
|
|
235
|
+
*
|
|
236
|
+
* `dir` selects the slide direction: an `enter` slides FROM the edge-displaced
|
|
237
|
+
* point TO [0,0]; an `exit` slides FROM [0,0] TO the edge-displaced point (so a
|
|
238
|
+
* back-timed exit reads as the inverse of the entrance). For an explicit
|
|
239
|
+
* `[Vec2,Vec2]` offset the endpoints are used verbatim (no direction flip).
|
|
240
|
+
*/
|
|
241
|
+
declare function transitionToClip(t: PresenceTransition, dir: 'enter' | 'exit'): Clip;
|
|
199
242
|
interface PresenceResult {
|
|
200
243
|
/** Reconciled tracks: the opacity guard (fused with enter/exit opacity keys) + any non-opacity channels. */
|
|
201
244
|
tracks: Track[];
|
|
@@ -213,4 +256,4 @@ interface PresenceResult {
|
|
|
213
256
|
*/
|
|
214
257
|
declare function presence(nodeId: TweenTarget, opts: PresenceOpts): PresenceResult;
|
|
215
258
|
//#endregion
|
|
216
|
-
export { type ApplyOpts, type ApplyOpts as ClipApplyOpts, type Box, type ChannelOverride, type Clip, type ClipChannel, ClipError, type ClipListDelay, type ClipListOpts, type ClipResult, type ClipSpec, type ClipTarget, type DurationOpts, MorphError, type MorphOpts, type MorphResult, type MorphTargets, PresenceError, type PresenceOpts, type PresenceResult, type SlideEdge, clip, clipList, driftLoop, morph, popIn, presence, pulse, slideIn };
|
|
259
|
+
export { type ApplyOpts, type ApplyOpts as ClipApplyOpts, type Box, type ChannelOverride, type Clip, type ClipChannel, ClipError, type ClipListDelay, type ClipListOpts, type ClipResult, type ClipSpec, type ClipTarget, type DurationOpts, MorphError, type MorphOpts, type MorphResult, type MorphTargets, PresenceError, type PresenceOpts, type PresenceResult, type PresenceTransition, type SlideEdge, clip, clipList, driftLoop, morph, popIn, presence, pulse, slideIn, transitionToClip };
|
package/dist/clips.js
CHANGED
|
@@ -398,6 +398,82 @@ function defaultExit() {
|
|
|
398
398
|
keys: [key(0, 1), key(DEFAULT_FADE, 0)]
|
|
399
399
|
} } });
|
|
400
400
|
}
|
|
401
|
+
/** A `PresenceTransition` is a plain bag; a `Clip` carries `apply`. Discriminate on that. */
|
|
402
|
+
function isClip(t) {
|
|
403
|
+
return typeof t.apply === "function";
|
|
404
|
+
}
|
|
405
|
+
/** Is a value a Vec2 ([number, number])? */
|
|
406
|
+
function isVec2(v) {
|
|
407
|
+
return Array.isArray(v);
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Compile an inline `PresenceTransition` literal into the SAME `Clip` an author
|
|
411
|
+
* would hand-write — an opacity channel (only when `opacity` is given), a position
|
|
412
|
+
* channel from `offset`+`edge` (slideIn convention), and a scale channel (scalar
|
|
413
|
+
* broadcast to Vec2, popIn convention). presence() then runs UNCHANGED on it.
|
|
414
|
+
*
|
|
415
|
+
* `dir` selects the slide direction: an `enter` slides FROM the edge-displaced
|
|
416
|
+
* point TO [0,0]; an `exit` slides FROM [0,0] TO the edge-displaced point (so a
|
|
417
|
+
* back-timed exit reads as the inverse of the entrance). For an explicit
|
|
418
|
+
* `[Vec2,Vec2]` offset the endpoints are used verbatim (no direction flip).
|
|
419
|
+
*/
|
|
420
|
+
function transitionToClip(t, dir) {
|
|
421
|
+
const d = t.dur ?? DEFAULT_FADE;
|
|
422
|
+
const ease = t.ease;
|
|
423
|
+
const channels = {};
|
|
424
|
+
if (t.opacity !== void 0) {
|
|
425
|
+
const [from, to] = t.opacity;
|
|
426
|
+
channels.opacity = {
|
|
427
|
+
path: "opacity",
|
|
428
|
+
keys: [key(0, from), key(d, to, ...easeArg(ease))]
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
if (t.offset !== void 0) {
|
|
432
|
+
const [from, to] = offsetEndpoints(t.offset, t.edge ?? "bottom", dir);
|
|
433
|
+
channels.offset = {
|
|
434
|
+
path: "position",
|
|
435
|
+
keys: [key(0, from), key(d, to, ...easeArg(ease))]
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
if (t.scale !== void 0) {
|
|
439
|
+
const [from, to] = scaleEndpoints(t.scale);
|
|
440
|
+
channels.scale = {
|
|
441
|
+
path: "scale",
|
|
442
|
+
keys: [key(0, from), key(d, to, ...easeArg(ease))]
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
return clip({ channels });
|
|
446
|
+
}
|
|
447
|
+
/** Spread-arg helper: pass `ease` to `key()` only when defined (no `undefined` arg). */
|
|
448
|
+
function easeArg(ease) {
|
|
449
|
+
return ease !== void 0 ? [ease] : [];
|
|
450
|
+
}
|
|
451
|
+
/** Edge → unit displacement direction (matches clipStdlib's slideIn `from` vectors). */
|
|
452
|
+
function edgeVec(edge, dist) {
|
|
453
|
+
return edge === "left" ? [-dist, 0] : edge === "right" ? [dist, 0] : edge === "top" ? [0, -dist] : [0, dist];
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Resolve the `offset` field to position [from, to] endpoints. A scalar slides that
|
|
457
|
+
* magnitude along `edge`; a single Vec2 is the displaced point; a [Vec2,Vec2] is
|
|
458
|
+
* verbatim endpoints. enter goes displaced→[0,0]; exit goes [0,0]→displaced.
|
|
459
|
+
*/
|
|
460
|
+
function offsetEndpoints(offset, edge, dir) {
|
|
461
|
+
if (Array.isArray(offset) && isVec2(offset[0])) return offset;
|
|
462
|
+
const displaced = isVec2(offset) ? offset : edgeVec(edge, offset);
|
|
463
|
+
const origin = [0, 0];
|
|
464
|
+
return dir === "enter" ? [displaced, origin] : [origin, displaced];
|
|
465
|
+
}
|
|
466
|
+
/** Resolve the `scale` field to [from, to] Vec2 endpoints (scalar pair → broadcast). */
|
|
467
|
+
function scaleEndpoints(scale) {
|
|
468
|
+
const [a, b] = scale;
|
|
469
|
+
const broadcast = (v) => isVec2(v) ? v : [v, v];
|
|
470
|
+
return [broadcast(a), broadcast(b)];
|
|
471
|
+
}
|
|
472
|
+
/** Normalize an enter/exit option (Clip or inline literal) to a Clip. */
|
|
473
|
+
function resolveTransition(t, dir, fallback) {
|
|
474
|
+
if (t === void 0) return fallback();
|
|
475
|
+
return isClip(t) ? t : transitionToClip(t, dir);
|
|
476
|
+
}
|
|
401
477
|
/** Effective duration of a clip after a speed multiplier (`apply` divides every t by speed). */
|
|
402
478
|
function effectiveDuration(c, opts) {
|
|
403
479
|
return c.duration / (opts?.speed ?? 1);
|
|
@@ -430,12 +506,14 @@ function partitionOpacity(tracks, opacityTarget) {
|
|
|
430
506
|
* presence('card', { show: 1, hide: 5 }) // fade in at 1, fade out to land on 5
|
|
431
507
|
*/
|
|
432
508
|
function presence(nodeId, opts) {
|
|
433
|
-
const
|
|
509
|
+
const show = opts.show ?? opts.window?.[0];
|
|
510
|
+
const hide = opts.hide ?? opts.window?.[1];
|
|
511
|
+
if (show === void 0 || hide === void 0) throw new PresenceError(`presence() needs a window: pass { show, hide } or { window: [show, hide] }`);
|
|
434
512
|
const opacityTarget = resolveTweenTarget(typeof nodeId === "string" ? `${nodeId}/opacity` : nodeId);
|
|
435
513
|
const lastSlash = opacityTarget.lastIndexOf("/");
|
|
436
514
|
const nodeIdStr = lastSlash < 0 ? opacityTarget : opacityTarget.slice(0, lastSlash);
|
|
437
|
-
const enter = opts.enter
|
|
438
|
-
const exit = opts.exit
|
|
515
|
+
const enter = resolveTransition(opts.enter, "enter", defaultEnter);
|
|
516
|
+
const exit = resolveTransition(opts.exit, "exit", defaultExit);
|
|
439
517
|
const enterRes = enter.apply(nodeIdStr, show, opts.enterOpts);
|
|
440
518
|
const enterEnd = show + effectiveDuration(enter, opts.enterOpts);
|
|
441
519
|
const exitDur = effectiveDuration(exit, opts.exitOpts);
|
|
@@ -479,4 +557,4 @@ function presence(nodeId, opts) {
|
|
|
479
557
|
};
|
|
480
558
|
}
|
|
481
559
|
//#endregion
|
|
482
|
-
export { ClipError, MorphError, PresenceError, clip, clipList, driftLoop, morph, popIn, presence, pulse, slideIn };
|
|
560
|
+
export { ClipError, MorphError, PresenceError, clip, clipList, driftLoop, morph, popIn, presence, pulse, slideIn, transitionToClip };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glissade/core",
|
|
3
|
-
"version": "0.18.0-pre.
|
|
3
|
+
"version": "0.18.0-pre.3",
|
|
4
4
|
"description": "glissade core: signals, tracks, timeline document, evaluation, easing, springs, seeded RNG. Zero DOM/Node dependencies.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"engines": {
|