@glissade/scene 0.57.0 → 0.57.1-pre.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/dist/describe.js +4 -4
- package/dist/motion.d.ts +12 -1
- package/dist/motion.js +12 -2
- package/package.json +2 -2
package/dist/describe.js
CHANGED
|
@@ -23,7 +23,7 @@ import { easings, listValueTypes } from "@glissade/core";
|
|
|
23
23
|
* never pulled onto the base embed path — a scene that never calls `describe()`
|
|
24
24
|
* pays zero bytes for it.
|
|
25
25
|
*/
|
|
26
|
-
const RAW_VERSION = "0.57.0";
|
|
26
|
+
const RAW_VERSION = "0.57.1-pre.0";
|
|
27
27
|
const PACKAGE_VERSION = RAW_VERSION.includes("GLISSADE_".concat("VERSION")) ? "0.0.0-dev" : RAW_VERSION;
|
|
28
28
|
/**
|
|
29
29
|
* Parse the documented positional-arg count from a helper `usage` string — the
|
|
@@ -586,13 +586,13 @@ const HELPERS = [
|
|
|
586
586
|
name: "particles",
|
|
587
587
|
summary: "A small SEEDED, BAKED particle emitter (FACTORY, no `new`): composes each() (count fixed slot nodes at `${id}/${i}`) + bake() (seeded physics → position/opacity/scale/rotation tracks on those SAME ids). Every slot is a real node with real tracks → a real exportable Lottie layer, faithful BY CONSTRUCTION (no render-only/custom-draw path). `count` is the MAX-CONCURRENT ring-buffer pool (bounded 200 — over THROWS, never clamps), NOT total emitted; opacity-0-for-the-whole-window slots are pruned so the layer count stays proportional. Seed defaults to hashStr(id); byte-identical run-to-run, a different seed varies. ESCAPE HATCH: `appearance` (any Node/glyph template), `step` (raw per-particle sim), `...` velocity/forces/lifetime. Tree-shakeable (@glissade/scene/motion).",
|
|
588
588
|
import: "@glissade/scene/motion",
|
|
589
|
-
usage: "particles(spec: { id, count, box: {w,h}, duration, fps, origin: [fx,fy], lifetime: number | [min,max], velocity: { speed:[min,max], angle:[min,max] (deg) }, appearance: (i, ctx) => Node | { node, opacityOverLife?, scaleOverLife? }, rate?, burst?: number | {at,n}[], seed?, area?, forces?: { gravity?, drag?, wind? }, spin?, opacityOverLife?, scaleOverLife?, step?: (p, dt, rng) => void }): { node: Group, tracks: Track[], end } — supply rate and/or burst; count > 200 throws."
|
|
589
|
+
usage: "particles(spec: { id, count, box: {w,h}, duration, fps, origin: [fx,fy], lifetime: number | [min,max], velocity: { speed:[min,max], angle:[min,max] (deg) }, appearance: (i, ctx) => Node | { node, opacityOverLife?, scaleOverLife? }, rate?, burst?: number | {at,n}[], seed?, area?, safeBottom? (relative [0,1] safe-area clamp — no spawn below this Y), forces?: { gravity?, drag?, wind? }, spin?, opacityOverLife?, scaleOverLife?, step?: (p, dt, rng) => void }): { node: Group, tracks: Track[], end } — supply rate and/or burst; count > 200 throws; safeBottom out-of-[0,1] or above the spawn-band top throws."
|
|
590
590
|
},
|
|
591
591
|
{
|
|
592
592
|
name: "drift",
|
|
593
|
-
summary: "Particles preset: ambient low-opacity motes floating gently up (a bokeh companion). Continuous low-rate; DEFAULTS to a small max-concurrent count (24) so the exported layer count stays proportional, NOT 200 near-empty layers. `appearance` is the primary control (a themed dot); `...rest` forwards to particles() (velocity/forces/lifetime/step). Factory (no `new`). Tree-shakeable (@glissade/scene/motion).",
|
|
593
|
+
summary: "Particles preset: ambient low-opacity motes floating gently up (a bokeh companion). Continuous low-rate; DEFAULTS to a small max-concurrent count (24) so the exported layer count stays proportional, NOT 200 near-empty layers. SAFE-AREA (0.57.1): the DEFAULT spawn band is centered + shallow (bottom ~0.68H) so bare drift() clears a standard lower-third caption safe-area by itself; pass `safeBottom` (relative [0,1]) to pin a consumer's exact captionTop, or override `area`/`origin` for a custom spawn region. `appearance` is the primary control (a themed dot); `...rest` forwards to particles() (velocity/forces/lifetime/area/safeBottom/step). Factory (no `new`). Tree-shakeable (@glissade/scene/motion).",
|
|
594
594
|
import: "@glissade/scene/motion",
|
|
595
|
-
usage: "drift(opts: { box: {w,h}, duration, fps, count?, rate?, origin?, color?, radius?, seed?, id?, ...rest (lifetime/velocity/forces/appearance/step) }): { node: Group, tracks: Track[], end }"
|
|
595
|
+
usage: "drift(opts: { box: {w,h}, duration, fps, count?, rate?, origin?, color?, radius?, seed?, id?, area?, safeBottom? (relative [0,1] — no motes below this Y, e.g. just above captionTop), ...rest (lifetime/velocity/forces/appearance/step) }): { node: Group, tracks: Track[], end }"
|
|
596
596
|
},
|
|
597
597
|
{
|
|
598
598
|
name: "sparks",
|
package/dist/motion.d.ts
CHANGED
|
@@ -305,6 +305,15 @@ interface ParticleSpec {
|
|
|
305
305
|
origin: Place;
|
|
306
306
|
/** Optional spread around the origin (px). */
|
|
307
307
|
area?: AreaSpec;
|
|
308
|
+
/**
|
|
309
|
+
* Safe-area clamp (0.57.1): no particle spawns BELOW this RELATIVE Y (`safeBottom *
|
|
310
|
+
* box.h`), so ambient motes never drift into a lower-third caption band. Relative
|
|
311
|
+
* [0,1] — NOT a pixel Y. Must sit at/below the spawn band's top (a `safeBottom` above
|
|
312
|
+
* the band top leaves no valid spawn region → throws). The framework can't know a
|
|
313
|
+
* consumer's captionTop, so this is the opt-in PRECISE clamp; the `drift` preset also
|
|
314
|
+
* ships a conservative DEFAULT band that clears a standard lower-third by itself.
|
|
315
|
+
*/
|
|
316
|
+
safeBottom?: number;
|
|
308
317
|
/** Polar initial velocity — `speed` px/s, `angle` degrees (0 = +x / right). */
|
|
309
318
|
velocity: {
|
|
310
319
|
speed: readonly [number, number];
|
|
@@ -347,6 +356,8 @@ interface ParticlePresetRest {
|
|
|
347
356
|
forces?: ParticleForces;
|
|
348
357
|
spin?: readonly [number, number];
|
|
349
358
|
area?: AreaSpec;
|
|
359
|
+
/** Safe-area clamp (relative [0,1]) — no spawn below this Y. See ParticleSpec.safeBottom. */
|
|
360
|
+
safeBottom?: number;
|
|
350
361
|
opacityOverLife?: OverLife;
|
|
351
362
|
scaleOverLife?: OverLife;
|
|
352
363
|
appearance?: (i: number, ctx: ParticleAppearanceContext) => Node | ParticleAppearance;
|
|
@@ -363,7 +374,7 @@ interface DriftOptions extends ParticlePresetRest {
|
|
|
363
374
|
count?: number;
|
|
364
375
|
/** Continuous emission rate, particles/sec (default 8). */
|
|
365
376
|
rate?: number;
|
|
366
|
-
/** Spawn point, relative viewport coords (default centered
|
|
377
|
+
/** Spawn point, relative viewport coords (default centered [0.5,0.5] — the conservative caption-safe band). */
|
|
367
378
|
origin?: Place;
|
|
368
379
|
/** Themed mote color (default a soft blue). */
|
|
369
380
|
color?: string;
|
package/dist/motion.js
CHANGED
|
@@ -403,6 +403,13 @@ function particles(spec) {
|
|
|
403
403
|
assertFiniteNum(spec.area.w, "area.w");
|
|
404
404
|
assertFiniteNum(spec.area.h, "area.h");
|
|
405
405
|
} else if (spec.area?.kind === "disc") assertFiniteNum(spec.area.radius, "area.radius");
|
|
406
|
+
if (spec.safeBottom !== void 0) {
|
|
407
|
+
const sb = assertFiniteNum(spec.safeBottom, "safeBottom");
|
|
408
|
+
if (sb < 0 || sb > 1) throw new ParticleError(`particles(): safeBottom must be a RELATIVE fraction in [0,1] (got ${sb}) — it is safeBottom*box.h, not a pixel Y (did you pass a captionTop in px?).`);
|
|
409
|
+
const areaHalfHRel = spec.area?.kind === "box" ? spec.area.h / 2 / spec.box.h : spec.area?.kind === "disc" ? spec.area.radius / spec.box.h : 0;
|
|
410
|
+
const bandTopRel = spec.origin[1] - areaHalfHRel;
|
|
411
|
+
if (sb < bandTopRel) throw new ParticleError(`particles(): safeBottom ${sb} is above the spawn band top (${bandTopRel.toFixed(3)}) — no valid spawn region (raise safeBottom, or lower the origin/shrink the area).`);
|
|
412
|
+
}
|
|
406
413
|
const emitTimes = buildEmitTimes(spec);
|
|
407
414
|
const opacityCurves = new Array(count);
|
|
408
415
|
const scaleCurves = new Array(count);
|
|
@@ -434,6 +441,7 @@ function particles(spec) {
|
|
|
434
441
|
const ox = spec.origin[0] * spec.box.w;
|
|
435
442
|
const oy = spec.origin[1] * spec.box.h;
|
|
436
443
|
const area = spec.area;
|
|
444
|
+
const safeBottomPx = spec.safeBottom !== void 0 ? spec.safeBottom * spec.box.h : void 0;
|
|
437
445
|
const emitDue = (w, rng) => {
|
|
438
446
|
const t = w.frame / spec.fps;
|
|
439
447
|
while (w.next < emitTimes.length && emitTimes[w.next] <= t + 1e-9) {
|
|
@@ -455,6 +463,7 @@ function particles(spec) {
|
|
|
455
463
|
px += Math.cos(th) * rr;
|
|
456
464
|
py += Math.sin(th) * rr;
|
|
457
465
|
}
|
|
466
|
+
if (safeBottomPx !== void 0 && py > safeBottomPx) py = safeBottomPx;
|
|
458
467
|
s.x = px;
|
|
459
468
|
s.y = py;
|
|
460
469
|
s.rot = 0;
|
|
@@ -556,6 +565,7 @@ function mergeSpec(base, rest) {
|
|
|
556
565
|
...rest.forces !== void 0 ? { forces: rest.forces } : {},
|
|
557
566
|
...rest.spin !== void 0 ? { spin: rest.spin } : {},
|
|
558
567
|
...rest.area !== void 0 ? { area: rest.area } : {},
|
|
568
|
+
...rest.safeBottom !== void 0 ? { safeBottom: rest.safeBottom } : {},
|
|
559
569
|
...rest.opacityOverLife !== void 0 ? { opacityOverLife: rest.opacityOverLife } : {},
|
|
560
570
|
...rest.scaleOverLife !== void 0 ? { scaleOverLife: rest.scaleOverLife } : {},
|
|
561
571
|
...rest.appearance !== void 0 ? { appearance: rest.appearance } : {},
|
|
@@ -584,7 +594,7 @@ function drift(opts) {
|
|
|
584
594
|
duration: opts.duration,
|
|
585
595
|
fps: opts.fps,
|
|
586
596
|
rate: opts.rate ?? 8,
|
|
587
|
-
origin: opts.origin ?? [.5, .
|
|
597
|
+
origin: opts.origin ?? [.5, .5],
|
|
588
598
|
lifetime: [3, 6],
|
|
589
599
|
velocity: {
|
|
590
600
|
speed: [4, 14],
|
|
@@ -594,7 +604,7 @@ function drift(opts) {
|
|
|
594
604
|
area: {
|
|
595
605
|
kind: "box",
|
|
596
606
|
w: opts.box.w * .8,
|
|
597
|
-
h: opts.box.h * .
|
|
607
|
+
h: opts.box.h * .36
|
|
598
608
|
},
|
|
599
609
|
opacityOverLife: fadeCurve(.5, .2, .35),
|
|
600
610
|
appearance: dotAppearance(color, radius)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glissade/scene",
|
|
3
|
-
"version": "0.57.0",
|
|
3
|
+
"version": "0.57.1-pre.0",
|
|
4
4
|
"description": "glissade scene graph: nodes, transforms, DisplayList emission. Renderer-agnostic; zero DOM/Node dependencies.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"engines": {
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
],
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"yoga-layout": "^3.2.1",
|
|
80
|
-
"@glissade/core": "0.57.0"
|
|
80
|
+
"@glissade/core": "0.57.1-pre.0"
|
|
81
81
|
},
|
|
82
82
|
"repository": {
|
|
83
83
|
"type": "git",
|