bireactive 0.2.0 → 0.2.2
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 +7 -7
- package/dist/{core/anim.d.ts → animation/animators.d.ts} +5 -3
- package/dist/{core/anim.js → animation/animators.js} +8 -5
- package/dist/animation/index.d.ts +1 -0
- package/dist/animation/index.js +1 -0
- package/dist/constraints/cluster.js +1 -1
- package/dist/constraints/expose.d.ts +17 -0
- package/dist/constraints/expose.js +61 -0
- package/dist/constraints/index.d.ts +1 -0
- package/dist/constraints/index.js +1 -0
- package/dist/constraints/linalg.d.ts +1 -8
- package/dist/constraints/linalg.js +5 -108
- package/dist/core/{signal.d.ts → cell.d.ts} +29 -6
- package/dist/core/{signal.js → cell.js} +134 -53
- package/dist/core/derived-geometry.d.ts +11 -0
- package/dist/core/derived-geometry.js +32 -0
- package/dist/core/index.d.ts +5 -10
- package/dist/core/index.js +5 -10
- package/dist/core/{aggregates.d.ts → lenses/aggregates.d.ts} +3 -14
- package/dist/core/{aggregates.js → lenses/aggregates.js} +5 -78
- package/dist/core/lenses/closed-form-policies.d.ts +6 -13
- package/dist/core/lenses/closed-form-policies.js +14 -24
- package/dist/core/lenses/decompositions.d.ts +14 -0
- package/dist/core/lenses/decompositions.js +224 -0
- package/dist/core/lenses/domain-aggregates.d.ts +10 -22
- package/dist/core/lenses/domain-aggregates.js +25 -39
- package/dist/core/{new-primitives.d.ts → lenses/geometry.d.ts} +11 -14
- package/dist/core/{new-primitives.js → lenses/geometry.js} +23 -37
- package/dist/core/lenses/index.d.ts +6 -4
- package/dist/core/lenses/index.js +6 -15
- package/dist/core/lenses/typed-factor.d.ts +1 -6
- package/dist/core/lenses/typed-factor.js +12 -114
- package/dist/core/{network-utils.d.ts → lifecycle.d.ts} +1 -1
- package/dist/core/{network-utils.js → lifecycle.js} +2 -2
- package/dist/core/linalg.d.ts +10 -0
- package/dist/core/linalg.js +109 -0
- package/dist/core/values/anchor.d.ts +1 -1
- package/dist/core/values/audio.d.ts +1 -1
- package/dist/core/values/audio.js +1 -1
- package/dist/core/values/bool.d.ts +1 -1
- package/dist/core/values/bool.js +1 -1
- package/dist/core/values/box.d.ts +2 -3
- package/dist/core/values/box.js +5 -6
- package/dist/core/values/canvas.d.ts +1 -1
- package/dist/core/values/canvas.js +2 -3
- package/dist/core/values/color.d.ts +2 -3
- package/dist/core/values/color.js +3 -4
- package/dist/core/values/flags.d.ts +1 -1
- package/dist/core/values/flags.js +1 -1
- package/dist/core/values/matrix.d.ts +1 -1
- package/dist/core/values/matrix.js +2 -3
- package/dist/core/values/num.d.ts +8 -3
- package/dist/core/values/num.js +22 -2
- package/dist/core/values/pose.d.ts +5 -1
- package/dist/core/values/pose.js +11 -1
- package/dist/core/values/range.d.ts +6 -4
- package/dist/core/values/range.js +16 -11
- package/dist/core/values/str.d.ts +1 -1
- package/dist/core/values/str.js +1 -1
- package/dist/core/values/template.d.ts +1 -1
- package/dist/core/values/transform.d.ts +2 -3
- package/dist/core/values/transform.js +2 -3
- package/dist/core/values/tri.d.ts +10 -8
- package/dist/core/values/tri.js +12 -12
- package/dist/core/values/vec.d.ts +10 -4
- package/dist/core/values/vec.js +30 -21
- package/dist/ext/timeline.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/propagators/layout.js +1 -1
- package/dist/shapes/handle.js +4 -4
- package/dist/shapes/shape.js +7 -7
- package/dist/shapes/transitions.js +2 -2
- package/package.json +7 -2
- package/dist/core/introspect.d.ts +0 -5
- package/dist/core/introspect.js +0 -31
- package/dist/core/lenses/factor-lens.d.ts +0 -42
- package/dist/core/lenses/factor-lens.js +0 -419
- package/dist/core/writable.d.ts +0 -15
- package/dist/core/writable.js +0 -29
- /package/dist/{core/tree.d.ts → tree.d.ts} +0 -0
- /package/dist/{core/tree.js → tree.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// cell.ts — symmetric bidirectional reactive engine.
|
|
2
2
|
//
|
|
3
3
|
// Forward propagation is alien-signals verbatim (link/propagate/
|
|
4
4
|
// checkDirty/shallowPropagate, Dirty/Pending/Recursed flags, lazy pull).
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
//
|
|
26
26
|
// Mode table — a cell's role is fully determined by which fields are set:
|
|
27
27
|
// source getter undefined (truth in currentValue)
|
|
28
|
-
//
|
|
28
|
+
// derived getter, no _bwd (read-only derived)
|
|
29
29
|
// lens 1→1 getter + _bwd{ put, parent: Cell }
|
|
30
30
|
// multi-out getter + _bwd{ put, parent: Cell[] } (1→N / N→M bwd)
|
|
31
31
|
// merge getter + _bwd{ merge } (N→1 backward fold)
|
|
@@ -411,8 +411,8 @@ export function lazy(self, key, make) {
|
|
|
411
411
|
export const isCell = (v) => v instanceof Cell;
|
|
412
412
|
/** Lens mode: a derived cell that can be written back (has a backward sidecar). */
|
|
413
413
|
export const isLens = (v) => v instanceof Cell && v.getter !== undefined && v._bwd !== undefined;
|
|
414
|
-
/**
|
|
415
|
-
export const
|
|
414
|
+
/** Read-only mode: derived with no backward path. */
|
|
415
|
+
export const isReadonly = (v) => v instanceof Cell && v.getter !== undefined && v._bwd === undefined;
|
|
416
416
|
export class Cell {
|
|
417
417
|
flags = F.Mutable;
|
|
418
418
|
subs;
|
|
@@ -540,6 +540,11 @@ export class Cell {
|
|
|
540
540
|
lens(fwd, bwd) {
|
|
541
541
|
return buildLens1(this.constructor, this, fwd, bwd, bwd.length >= 2);
|
|
542
542
|
}
|
|
543
|
+
/** Read-only same-type view: the RO dual of the endo `.lens`. For a cross-type view use the typed static
|
|
544
|
+
* `Target.derive(src, fn)`. */
|
|
545
|
+
derive(fn) {
|
|
546
|
+
return buildDerived(this.constructor, () => fn(this.value));
|
|
547
|
+
}
|
|
543
548
|
/** Backward-aggregating node — bwd dual of computed. Forward, the
|
|
544
549
|
* identity view of its parent; backward, folds contributions from
|
|
545
550
|
* upstream lenses (slot-keyed) and direct writes (DIRECT_SLOT). */
|
|
@@ -558,22 +563,11 @@ export class Cell {
|
|
|
558
563
|
}
|
|
559
564
|
// biome-ignore lint/suspicious/noExplicitAny: dispatch
|
|
560
565
|
static derive(...args) {
|
|
561
|
-
|
|
562
|
-
return buildComputed(this, args[0]);
|
|
563
|
-
const [parent, fn] = args;
|
|
564
|
-
if (Array.isArray(parent))
|
|
565
|
-
return buildLensN(this, parent, fn, undefined, false);
|
|
566
|
-
return buildComputed(this, () => fn(parent.value));
|
|
566
|
+
return dispatchDerive(this, args);
|
|
567
567
|
}
|
|
568
568
|
// biome-ignore lint/suspicious/noExplicitAny: dispatch
|
|
569
569
|
static lens(...args) {
|
|
570
|
-
|
|
571
|
-
if (args.length === 2)
|
|
572
|
-
return buildStateful(this, Array.isArray(parent) ? parent : [parent], a);
|
|
573
|
-
const readsSource = b.length >= 2;
|
|
574
|
-
if (Array.isArray(parent))
|
|
575
|
-
return buildLensN(this, parent, a, b, readsSource);
|
|
576
|
-
return buildLens1(this, parent, a, b, readsSource);
|
|
570
|
+
return dispatchLens(this, args);
|
|
577
571
|
}
|
|
578
572
|
/** Type predicate against this class: `Vec.is(x)` narrows `x` to `Vec`.
|
|
579
573
|
* Inherited static; works for any subclass via polymorphic `this`. */
|
|
@@ -616,14 +610,14 @@ export class Cell {
|
|
|
616
610
|
// Read-only ⇔ computed: a getter with no backward sidecar.
|
|
617
611
|
const ro = parent.getter !== undefined && parent._bwd === undefined;
|
|
618
612
|
if (ro) {
|
|
619
|
-
return
|
|
613
|
+
return buildDerived(ctor, () => get(parent.value));
|
|
620
614
|
}
|
|
621
615
|
// Spread-replace reads the current source ⇒ source-reading (lens) form.
|
|
622
616
|
return buildLens1(ctor, parent, get, (v, s) => ({ ...s, [key]: v }), true);
|
|
623
617
|
}
|
|
624
618
|
}
|
|
625
619
|
// biome-ignore lint/suspicious/noExplicitAny: variance escape
|
|
626
|
-
function
|
|
620
|
+
function buildDerived(Cls, getter) {
|
|
627
621
|
const cell = new Cls();
|
|
628
622
|
cell.getter = getter;
|
|
629
623
|
cell.flags = F.Mutable | F.Dirty;
|
|
@@ -701,7 +695,58 @@ spec) {
|
|
|
701
695
|
});
|
|
702
696
|
return cell;
|
|
703
697
|
}
|
|
704
|
-
//
|
|
698
|
+
// Single-source stateful lens: the `buildLens1` of the complement path.
|
|
699
|
+
// Drops the per-read copy/external loops to direct index-0 access; the
|
|
700
|
+
// spec stays array-shaped (`init: ([s]) => …`), so a reused length-1
|
|
701
|
+
// `vals` still feeds the closures and `b.parent` stays an array for the
|
|
702
|
+
// shared split backward path.
|
|
703
|
+
// biome-ignore lint/suspicious/noExplicitAny: variance escape
|
|
704
|
+
function buildStateful1(Cls, parent,
|
|
705
|
+
// biome-ignore lint/suspicious/noExplicitAny: opaque spec
|
|
706
|
+
spec) {
|
|
707
|
+
const cell = new Cls();
|
|
708
|
+
cell.flags = F.Mutable | F.Dirty;
|
|
709
|
+
const b = (cell._bwd = new BwdSpec());
|
|
710
|
+
const sc = (b.stateful = new StatefulCore(spec.init([parent.peek()]), spec.fwd, spec.step));
|
|
711
|
+
b.put = spec.bwd;
|
|
712
|
+
b.parent = [parent];
|
|
713
|
+
const vals = [undefined];
|
|
714
|
+
cell.getter = (() => {
|
|
715
|
+
const v = (vals[0] = parent.value);
|
|
716
|
+
const lb = sc.lastBwd;
|
|
717
|
+
const external = lb === undefined || lb[0] !== v;
|
|
718
|
+
sc.complement = sc.step(vals, sc.complement, external);
|
|
719
|
+
return sc.fwd(vals, sc.complement);
|
|
720
|
+
});
|
|
721
|
+
return cell;
|
|
722
|
+
}
|
|
723
|
+
// Shared runtime dispatch for `derive`/`lens`, parameterized by the cell
|
|
724
|
+
// constructor: the polymorphic-`this` statics pass the typed subclass
|
|
725
|
+
// (`Vec.derive` → Vec), the free functions pass the plain `Cell`. One body
|
|
726
|
+
// each so the static and free forms can't drift (typed overloads live at
|
|
727
|
+
// the call sites; only these `any` runtime bodies are shared).
|
|
728
|
+
// biome-ignore lint/suspicious/noExplicitAny: dispatch
|
|
729
|
+
function dispatchDerive(ctor, args) {
|
|
730
|
+
if (args.length === 1)
|
|
731
|
+
return buildDerived(ctor, args[0]);
|
|
732
|
+
const [parent, fn] = args;
|
|
733
|
+
if (Array.isArray(parent))
|
|
734
|
+
return buildLensN(ctor, parent, fn, undefined, false);
|
|
735
|
+
return buildDerived(ctor, () => fn(parent.value));
|
|
736
|
+
}
|
|
737
|
+
// biome-ignore lint/suspicious/noExplicitAny: dispatch
|
|
738
|
+
function dispatchLens(ctor, args) {
|
|
739
|
+
const [parent, a, b] = args;
|
|
740
|
+
if (args.length === 2) {
|
|
741
|
+
const ps = Array.isArray(parent) ? parent : [parent];
|
|
742
|
+
return ps.length === 1 ? buildStateful1(ctor, ps[0], a) : buildStateful(ctor, ps, a);
|
|
743
|
+
}
|
|
744
|
+
const readsSource = b.length >= 2;
|
|
745
|
+
if (Array.isArray(parent))
|
|
746
|
+
return buildLensN(ctor, parent, a, b, readsSource);
|
|
747
|
+
return buildLens1(ctor, parent, a, b, readsSource);
|
|
748
|
+
}
|
|
749
|
+
// Install `value` on the prototype (for silly TypeScript inference reasons I'd like to avoid if we can figure it out).
|
|
705
750
|
Object.defineProperty(Cell.prototype, "value", {
|
|
706
751
|
get() {
|
|
707
752
|
const flags = this.flags;
|
|
@@ -986,35 +1031,17 @@ export function cell(initial, opts) {
|
|
|
986
1031
|
return initial;
|
|
987
1032
|
return new Cell(initial, opts);
|
|
988
1033
|
}
|
|
989
|
-
export function computed(fn) {
|
|
990
|
-
const cell = new Cell(undefined);
|
|
991
|
-
cell.flags = F.Mutable | F.Dirty;
|
|
992
|
-
cell.getter = fn;
|
|
993
|
-
return cell;
|
|
994
|
-
}
|
|
995
1034
|
// Bare (untyped) factories. Construct a plain `Cell`, inferring `R`
|
|
996
1035
|
// from the closures (the polymorphic-`this` statics are for typed
|
|
997
1036
|
// subclasses like `Vec.lens`).
|
|
998
1037
|
const CELL_CTOR = Cell;
|
|
999
1038
|
// biome-ignore lint/suspicious/noExplicitAny: dispatch
|
|
1000
1039
|
export function derive(...args) {
|
|
1001
|
-
|
|
1002
|
-
return buildComputed(CELL_CTOR, args[0]);
|
|
1003
|
-
const [parent, fn] = args;
|
|
1004
|
-
if (Array.isArray(parent))
|
|
1005
|
-
return buildLensN(CELL_CTOR, parent, fn, undefined, false);
|
|
1006
|
-
return buildComputed(CELL_CTOR, () => fn(parent.value));
|
|
1040
|
+
return dispatchDerive(CELL_CTOR, args);
|
|
1007
1041
|
}
|
|
1008
1042
|
// biome-ignore lint/suspicious/noExplicitAny: dispatch
|
|
1009
1043
|
export function lens(...args) {
|
|
1010
|
-
|
|
1011
|
-
if (args.length === 2) {
|
|
1012
|
-
return buildStateful(CELL_CTOR, Array.isArray(parent) ? parent : [parent], a);
|
|
1013
|
-
}
|
|
1014
|
-
const readsSource = b.length >= 2;
|
|
1015
|
-
if (Array.isArray(parent))
|
|
1016
|
-
return buildLensN(CELL_CTOR, parent, a, b, readsSource);
|
|
1017
|
-
return buildLens1(CELL_CTOR, parent, a, b, readsSource);
|
|
1044
|
+
return dispatchLens(CELL_CTOR, args);
|
|
1018
1045
|
}
|
|
1019
1046
|
// Effect — alien-signals verbatim.
|
|
1020
1047
|
class Effect {
|
|
@@ -1240,11 +1267,11 @@ class _NetworkNode {
|
|
|
1240
1267
|
}
|
|
1241
1268
|
_computeDirty() {
|
|
1242
1269
|
let dirty;
|
|
1243
|
-
for (const [
|
|
1244
|
-
if (
|
|
1270
|
+
for (const [cell, lastVal] of this.lastValues) {
|
|
1271
|
+
if (cell.peek() !== lastVal) {
|
|
1245
1272
|
if (dirty === undefined)
|
|
1246
1273
|
dirty = new Set();
|
|
1247
|
-
dirty.add(
|
|
1274
|
+
dirty.add(cell);
|
|
1248
1275
|
}
|
|
1249
1276
|
}
|
|
1250
1277
|
return dirty ?? EMPTY_DIRTY;
|
|
@@ -1273,8 +1300,8 @@ class _NetworkNode {
|
|
|
1273
1300
|
this.lastValues.clear();
|
|
1274
1301
|
let l = this.deps;
|
|
1275
1302
|
while (l !== undefined) {
|
|
1276
|
-
const
|
|
1277
|
-
this.lastValues.set(
|
|
1303
|
+
const cell = l.dep;
|
|
1304
|
+
this.lastValues.set(cell, cell.peek());
|
|
1278
1305
|
l = l.nextDep;
|
|
1279
1306
|
}
|
|
1280
1307
|
}
|
|
@@ -1289,16 +1316,16 @@ class _NetworkNode {
|
|
|
1289
1316
|
}
|
|
1290
1317
|
this._runBody(this._computeDirty());
|
|
1291
1318
|
}
|
|
1292
|
-
subscribe(
|
|
1319
|
+
subscribe(cells) {
|
|
1293
1320
|
if (this.disposed)
|
|
1294
1321
|
return;
|
|
1295
|
-
this._linkBatch(
|
|
1322
|
+
this._linkBatch(cells);
|
|
1296
1323
|
}
|
|
1297
|
-
unsubscribe(
|
|
1324
|
+
unsubscribe(cells) {
|
|
1298
1325
|
if (this.disposed)
|
|
1299
1326
|
return;
|
|
1300
1327
|
const set = this._depsSet;
|
|
1301
|
-
for (const s of
|
|
1328
|
+
for (const s of cells) {
|
|
1302
1329
|
if (!set.has(s))
|
|
1303
1330
|
continue;
|
|
1304
1331
|
set.delete(s);
|
|
@@ -1312,7 +1339,7 @@ class _NetworkNode {
|
|
|
1312
1339
|
}
|
|
1313
1340
|
}
|
|
1314
1341
|
}
|
|
1315
|
-
_linkBatch(
|
|
1342
|
+
_linkBatch(cells) {
|
|
1316
1343
|
const set = this._depsSet;
|
|
1317
1344
|
let tail = this.deps;
|
|
1318
1345
|
if (tail !== undefined) {
|
|
@@ -1320,7 +1347,7 @@ class _NetworkNode {
|
|
|
1320
1347
|
tail = tail.nextDep;
|
|
1321
1348
|
}
|
|
1322
1349
|
this.depsTail = tail;
|
|
1323
|
-
for (const s of
|
|
1350
|
+
for (const s of cells) {
|
|
1324
1351
|
if (set.has(s))
|
|
1325
1352
|
continue;
|
|
1326
1353
|
set.add(s);
|
|
@@ -1341,9 +1368,63 @@ deps, body, opts) {
|
|
|
1341
1368
|
const handle = {
|
|
1342
1369
|
dispose: () => node._unwatched(),
|
|
1343
1370
|
flush: () => node.flush(),
|
|
1344
|
-
subscribe: (...
|
|
1345
|
-
unsubscribe: (...
|
|
1371
|
+
subscribe: (...cells) => node.subscribe(cells),
|
|
1372
|
+
unsubscribe: (...cells) => node.unsubscribe(cells),
|
|
1346
1373
|
};
|
|
1347
1374
|
node._initWithHandle(handle, deps);
|
|
1348
1375
|
return handle;
|
|
1349
1376
|
}
|
|
1377
|
+
// MISC stuff used by a few places, to revisit...
|
|
1378
|
+
// ── value-class authoring helpers ──────────────────────────────────
|
|
1379
|
+
//
|
|
1380
|
+
// `field`/`cachedDerive` are the two getter forms a value class declares.
|
|
1381
|
+
// The choice between them IS the local declaration of writability at each
|
|
1382
|
+
// getter (mirroring `: this` invertible method returns). For arbitrary
|
|
1383
|
+
// cached views, use `lazy()` directly.
|
|
1384
|
+
/** Bidirectional field lens onto `parent.value[key]`; write spread-
|
|
1385
|
+
* replaces the composite. Cached per (instance, key). Return type is
|
|
1386
|
+
* conditional: `Writable<Cls>` on a writable parent, bare `Cls` on RO.
|
|
1387
|
+
*
|
|
1388
|
+
* get x() { return field(this, "x", Num); } */
|
|
1389
|
+
export function field(parent, key, Cls) {
|
|
1390
|
+
return lazy(parent, key, () => Cell.fieldOf(parent, key, Cls));
|
|
1391
|
+
}
|
|
1392
|
+
/** Read-only derived view via `Cls.derive(parent, fn)`, memoized per
|
|
1393
|
+
* (instance, key); always bare `Cls` (RO). The cache is the point — the
|
|
1394
|
+
* getter form, not a new kind of cell.
|
|
1395
|
+
*
|
|
1396
|
+
* get magnitude() {
|
|
1397
|
+
* return cachedDerive(this, "magnitude", Num, v => Math.hypot(v.x, v.y));
|
|
1398
|
+
* } */
|
|
1399
|
+
// biome-ignore lint/suspicious/noExplicitAny: variance escape, mirrors Cls.derive
|
|
1400
|
+
export function cachedDerive(parent, key, Cls, fn) {
|
|
1401
|
+
// biome-ignore lint/suspicious/noExplicitAny: variance escape on Cls.derive
|
|
1402
|
+
return lazy(parent, key, () => Cls.derive(parent, fn));
|
|
1403
|
+
}
|
|
1404
|
+
/** Every cell `s` transitively depends on, including itself. Raw cells
|
|
1405
|
+
* return `{s}`; lens chains return the chain plus all parents. BFS,
|
|
1406
|
+
* peeking each Computed to populate deps; the `seen` set breaks cycles.
|
|
1407
|
+
* Used by `Propagators` to expand declared reads into their transitive
|
|
1408
|
+
* parent set. Inspection is safe: it only reads engine state and peeks
|
|
1409
|
+
* `.value` (idempotent for lazy Computeds). */
|
|
1410
|
+
export function transitiveDeps(s) {
|
|
1411
|
+
const seen = new Set();
|
|
1412
|
+
const queue = [s];
|
|
1413
|
+
while (queue.length > 0) {
|
|
1414
|
+
const cur = queue.shift();
|
|
1415
|
+
if (seen.has(cur))
|
|
1416
|
+
continue;
|
|
1417
|
+
seen.add(cur);
|
|
1418
|
+
// Cast to reach engine fields the typed Cell<T> shape doesn't surface.
|
|
1419
|
+
const c = cur;
|
|
1420
|
+
if (c.getter !== undefined) {
|
|
1421
|
+
void cur.value;
|
|
1422
|
+
let l = c.deps;
|
|
1423
|
+
while (l !== undefined) {
|
|
1424
|
+
queue.push(l.dep);
|
|
1425
|
+
l = l.nextDep;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
return seen;
|
|
1430
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Cell } from "./cell.js";
|
|
2
|
+
import { Vec } from "./values/vec.js";
|
|
3
|
+
type V = {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
};
|
|
7
|
+
/** Quadratic Bézier point at parameter `t`. RO. */
|
|
8
|
+
export declare function bezier2(p0: Cell<V>, p1: Cell<V>, p2: Cell<V>, t: Cell<number>): Vec;
|
|
9
|
+
/** Cubic Bézier point at parameter `t`. RO. */
|
|
10
|
+
export declare function bezier3(p0: Cell<V>, p1: Cell<V>, p2: Cell<V>, p3: Cell<V>, t: Cell<number>): Vec;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// derived-geometry.ts — read-only geometric readouts over `Cls.derive`.
|
|
2
|
+
//
|
|
3
|
+
// One-way derives whose inverse is genuinely under-determined (a point
|
|
4
|
+
// sampled at parameter `t` constrains the curve at one point, but the
|
|
5
|
+
// control points have many DOF). They live here, off the lens surface,
|
|
6
|
+
// to keep `lenses/` exclusively bidirectional. For the writable bezier
|
|
7
|
+
// shape decomposition see `bezierGestalt` in `lenses/domain-aggregates`.
|
|
8
|
+
import { Vec } from "./values/vec.js";
|
|
9
|
+
/** Quadratic Bézier point at parameter `t`. RO. */
|
|
10
|
+
export function bezier2(p0, p1, p2, t) {
|
|
11
|
+
return Vec.derive([p0, p1, p2, t], vals => {
|
|
12
|
+
const [a, b, c, tv] = vals;
|
|
13
|
+
const u = 1 - tv;
|
|
14
|
+
return {
|
|
15
|
+
x: u * u * a.x + 2 * u * tv * b.x + tv * tv * c.x,
|
|
16
|
+
y: u * u * a.y + 2 * u * tv * b.y + tv * tv * c.y,
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** Cubic Bézier point at parameter `t`. RO. */
|
|
21
|
+
export function bezier3(p0, p1, p2, p3, t) {
|
|
22
|
+
return Vec.derive([p0, p1, p2, p3, t], vals => {
|
|
23
|
+
const [a, b, c, d, tv] = vals;
|
|
24
|
+
const u = 1 - tv;
|
|
25
|
+
const u2 = u * u;
|
|
26
|
+
const t2 = tv * tv;
|
|
27
|
+
return {
|
|
28
|
+
x: u2 * u * a.x + 3 * u2 * tv * b.x + 3 * u * t2 * c.x + t2 * tv * d.x,
|
|
29
|
+
y: u2 * u * a.y + 3 * u2 * tv * b.y + 3 * u * t2 * c.y + t2 * tv * d.y,
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export { transitiveDeps } from "./introspect.js";
|
|
1
|
+
export { batch, Cell, type CellOptions, cachedDerive, cell, derive, effect, field, type Init, type Inner, isCell, isLens, isReadonly, lazy, lens, type Network, network, type Read, reader, readNow, type StatefulBwd, type StatefulLensSpec, setCellWriteHook, transitiveDeps, untracked, type Val, type Writable, type WritableBrand, } from "./cell.js";
|
|
2
|
+
export { bezier2, bezier3 } from "./derived-geometry.js";
|
|
4
3
|
export * from "./lenses/index.js";
|
|
5
|
-
export { each, type Lifecycle } from "./
|
|
6
|
-
export { reflectionLens } from "./new-primitives.js";
|
|
7
|
-
export { batch, Cell, type CellOptions, cell, derive, effect, type Init, type Inner, isCell, isComputed, isLens, lazy, lens, type Network, network, type Read, reader, readNow, type StatefulBwd, type StatefulLensSpec, setCellWriteHook, untracked, type Val, type Writable, type WritableBrand, } from "./signal.js";
|
|
4
|
+
export { each, type Lifecycle } from "./lifecycle.js";
|
|
8
5
|
export { type Equals, type Lerp, type Linear, type Metric, type Pack, type Pivotal, requireEquals, requireLerp, requireLinear, requireMetric, requirePack, requirePivotal, type TraitDict, type Traits, } from "./traits.js";
|
|
9
|
-
export { allNodes, atPath, isLeaf, leavesOf, node as treeNode, nodeCount, type TreeNode, walkTree, } from "./tree.js";
|
|
10
6
|
export { Anchor, Dir } from "./values/anchor.js";
|
|
11
7
|
export { Audio, type AudioClip, audio, stamp as audioStamp } from "./values/audio.js";
|
|
12
8
|
export * as BoolMath from "./values/bool.js";
|
|
13
9
|
export { Bool, bool } from "./values/bool.js";
|
|
14
10
|
export * as BoxMath from "./values/box.js";
|
|
15
|
-
export { Box, box
|
|
11
|
+
export { Box, box } from "./values/box.js";
|
|
16
12
|
export { Canvas, canvas, type Raster, stamp as canvasStamp } from "./values/canvas.js";
|
|
17
13
|
export * as ColorMath from "./values/color.js";
|
|
18
14
|
export { Color, rgb, rgba } from "./values/color.js";
|
|
19
15
|
export { Flags, flags } from "./values/flags.js";
|
|
20
16
|
export { blit as gpuBlit, brush as gpuBrush, copy as gpuCopy, newTex as gpuNewTex, Spring, scratch2 as gpuScratch2, type Tex, } from "./values/gpu.js";
|
|
21
17
|
export * as MatrixMath from "./values/matrix.js";
|
|
22
|
-
export {
|
|
18
|
+
export { Matrix, matrix, transformBox, transformPoint } from "./values/matrix.js";
|
|
23
19
|
export * as NumMath from "./values/num.js";
|
|
24
20
|
export { Num, num } from "./values/num.js";
|
|
25
21
|
export * as PoseMath from "./values/pose.js";
|
|
@@ -35,4 +31,3 @@ export * as TriMath from "./values/tri.js";
|
|
|
35
31
|
export { Tri, tri } from "./values/tri.js";
|
|
36
32
|
export * as VecMath from "./values/vec.js";
|
|
37
33
|
export { type PolarPolicy, polar, tangentPoint, Vec, vec } from "./values/vec.js";
|
|
38
|
-
export { derived, field } from "./writable.js";
|
package/dist/core/index.js
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export { transitiveDeps } from "./introspect.js";
|
|
1
|
+
export { batch, Cell, cachedDerive, cell, derive, effect, field, isCell, isLens, isReadonly, lazy, lens, network, reader, readNow, setCellWriteHook, transitiveDeps, untracked, } from "./cell.js";
|
|
2
|
+
export { bezier2, bezier3 } from "./derived-geometry.js";
|
|
4
3
|
export * from "./lenses/index.js";
|
|
5
|
-
export { each } from "./
|
|
6
|
-
export { reflectionLens } from "./new-primitives.js";
|
|
7
|
-
export { batch, Cell, cell, derive, effect, isCell, isComputed, isLens, lazy, lens, network, reader, readNow, setCellWriteHook, untracked, } from "./signal.js";
|
|
4
|
+
export { each } from "./lifecycle.js";
|
|
8
5
|
export { requireEquals, requireLerp, requireLinear, requireMetric, requirePack, requirePivotal, } from "./traits.js";
|
|
9
|
-
export { allNodes, atPath, isLeaf, leavesOf, node as treeNode, nodeCount, walkTree, } from "./tree.js";
|
|
10
6
|
export { Anchor, Dir } from "./values/anchor.js";
|
|
11
7
|
export { Audio, audio, stamp as audioStamp } from "./values/audio.js";
|
|
12
8
|
export * as BoolMath from "./values/bool.js";
|
|
13
9
|
export { Bool, bool } from "./values/bool.js";
|
|
14
10
|
export * as BoxMath from "./values/box.js";
|
|
15
|
-
export { Box, box
|
|
11
|
+
export { Box, box } from "./values/box.js";
|
|
16
12
|
export { Canvas, canvas, stamp as canvasStamp } from "./values/canvas.js";
|
|
17
13
|
export * as ColorMath from "./values/color.js";
|
|
18
14
|
export { Color, rgb, rgba } from "./values/color.js";
|
|
19
15
|
export { Flags, flags } from "./values/flags.js";
|
|
20
16
|
export { blit as gpuBlit, brush as gpuBrush, copy as gpuCopy, newTex as gpuNewTex, Spring, scratch2 as gpuScratch2, } from "./values/gpu.js";
|
|
21
17
|
export * as MatrixMath from "./values/matrix.js";
|
|
22
|
-
export {
|
|
18
|
+
export { Matrix, matrix, transformBox, transformPoint } from "./values/matrix.js";
|
|
23
19
|
export * as NumMath from "./values/num.js";
|
|
24
20
|
export { Num, num } from "./values/num.js";
|
|
25
21
|
export * as PoseMath from "./values/pose.js";
|
|
@@ -35,4 +31,3 @@ export * as TriMath from "./values/tri.js";
|
|
|
35
31
|
export { Tri, tri } from "./values/tri.js";
|
|
36
32
|
export * as VecMath from "./values/vec.js";
|
|
37
33
|
export { polar, tangentPoint, Vec, vec } from "./values/vec.js";
|
|
38
|
-
export { derived, field } from "./writable.js";
|
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { Num } from "
|
|
3
|
-
import { Vec } from "
|
|
4
|
-
type V = {
|
|
5
|
-
x: number;
|
|
6
|
-
y: number;
|
|
7
|
-
};
|
|
8
|
-
/** Equal-weight mean of N Linear values; writes distribute the delta evenly. */
|
|
9
|
-
export declare function meanLens<T, C extends new (...args: never[]) => Cell<any>>(Cls: C, parents: readonly Cell<T>[]): Writable<InstanceType<C>>;
|
|
10
|
-
/** Midpoint of two writable Vecs. Drag-translates both endpoints. */
|
|
11
|
-
export declare function midpointLens(a: Cell<V>, b: Cell<V>): Writable<Vec>;
|
|
12
|
-
/** Centroid of N writable Vecs. Drag-translates all members. */
|
|
13
|
-
export declare function centroidLens(parents: readonly Cell<V>[]): Writable<Vec>;
|
|
1
|
+
import type { Writable } from "../cell.js";
|
|
2
|
+
import { Num } from "../values/num.js";
|
|
3
|
+
import { Vec } from "../values/vec.js";
|
|
14
4
|
export interface ArgminOpts {
|
|
15
5
|
/** Finite-difference epsilon for the Jacobian. Default 1e-4. */
|
|
16
6
|
eps?: number;
|
|
@@ -61,4 +51,3 @@ export declare function argminVec(inputs: readonly Num[], forward: (xs: readonly
|
|
|
61
51
|
x: number;
|
|
62
52
|
y: number;
|
|
63
53
|
}, weights: readonly number[], opts?: ArgminVecOpts): Writable<Vec>;
|
|
64
|
-
export {};
|
|
@@ -1,85 +1,12 @@
|
|
|
1
|
-
// aggregates.ts — N→1
|
|
2
|
-
// `Cls.
|
|
1
|
+
// aggregates.ts — numerical N→1 / N→M argmin lens primitives over
|
|
2
|
+
// `Cls.lens`. For the closed-form equal-weight `mean` and `spread`
|
|
3
|
+
// aggregates see `domain-aggregates.ts`.
|
|
3
4
|
//
|
|
4
5
|
// All route through the engine's N-input lens path. Stateless-bwd
|
|
5
6
|
// (`(target) => updates`) skips the peek loop on the hot path;
|
|
6
7
|
// stateful-bwd (`(target, vals) => updates`) reads the scratch.
|
|
7
|
-
import { Num } from "
|
|
8
|
-
import { Vec } from "
|
|
9
|
-
/** Equal-weight mean of N Linear values; writes distribute the delta evenly. */
|
|
10
|
-
// biome-ignore lint/suspicious/noExplicitAny: variance escape, mirrors Cls.lens
|
|
11
|
-
export function meanLens(Cls, parents) {
|
|
12
|
-
const lin = (Cls.traits?.linear ??
|
|
13
|
-
(() => {
|
|
14
|
-
throw new Error("meanLens: value class has no 'linear' trait");
|
|
15
|
-
})());
|
|
16
|
-
const n = parents.length;
|
|
17
|
-
const inv = 1 / n;
|
|
18
|
-
// biome-ignore lint/suspicious/noExplicitAny: variance escape on Cls.lens
|
|
19
|
-
return Cls.lens(parents,
|
|
20
|
-
// biome-ignore lint/suspicious/noExplicitAny: tuple-vs-array variance
|
|
21
|
-
(vals) => {
|
|
22
|
-
let acc = vals[0];
|
|
23
|
-
for (let i = 1; i < n; i++)
|
|
24
|
-
acc = lin.add(acc, vals[i]);
|
|
25
|
-
return lin.scale(acc, inv);
|
|
26
|
-
},
|
|
27
|
-
// biome-ignore lint/suspicious/noExplicitAny: tuple-vs-array variance
|
|
28
|
-
(target, vals) => {
|
|
29
|
-
let cur = vals[0];
|
|
30
|
-
for (let i = 1; i < n; i++)
|
|
31
|
-
cur = lin.add(cur, vals[i]);
|
|
32
|
-
cur = lin.scale(cur, inv);
|
|
33
|
-
const delta = lin.sub(target, cur);
|
|
34
|
-
const out = new Array(n);
|
|
35
|
-
for (let i = 0; i < n; i++)
|
|
36
|
-
out[i] = lin.add(vals[i], delta);
|
|
37
|
-
return out;
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
/** Midpoint of two writable Vecs. Drag-translates both endpoints. */
|
|
41
|
-
export function midpointLens(a, b) {
|
|
42
|
-
return Vec.lens([a, b], vals => {
|
|
43
|
-
const [av, bv] = vals;
|
|
44
|
-
return { x: (av.x + bv.x) / 2, y: (av.y + bv.y) / 2 };
|
|
45
|
-
}, (target, vals) => {
|
|
46
|
-
const [av, bv] = vals;
|
|
47
|
-
const dx = target.x - (av.x + bv.x) / 2;
|
|
48
|
-
const dy = target.y - (av.y + bv.y) / 2;
|
|
49
|
-
return [
|
|
50
|
-
{ x: av.x + dx, y: av.y + dy },
|
|
51
|
-
{ x: bv.x + dx, y: bv.y + dy },
|
|
52
|
-
];
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
/** Centroid of N writable Vecs. Drag-translates all members. */
|
|
56
|
-
export function centroidLens(parents) {
|
|
57
|
-
const n = parents.length;
|
|
58
|
-
const inv = 1 / n;
|
|
59
|
-
return Vec.lens(parents, vals => {
|
|
60
|
-
const arr = vals;
|
|
61
|
-
let sx = 0, sy = 0;
|
|
62
|
-
for (let i = 0; i < n; i++) {
|
|
63
|
-
sx += arr[i].x;
|
|
64
|
-
sy += arr[i].y;
|
|
65
|
-
}
|
|
66
|
-
return { x: sx * inv, y: sy * inv };
|
|
67
|
-
}, (target, vals) => {
|
|
68
|
-
const arr = vals;
|
|
69
|
-
let sx = 0, sy = 0;
|
|
70
|
-
for (let i = 0; i < n; i++) {
|
|
71
|
-
sx += arr[i].x;
|
|
72
|
-
sy += arr[i].y;
|
|
73
|
-
}
|
|
74
|
-
const dx = target.x - sx * inv;
|
|
75
|
-
const dy = target.y - sy * inv;
|
|
76
|
-
const out = new Array(n);
|
|
77
|
-
for (let i = 0; i < n; i++) {
|
|
78
|
-
out[i] = { x: arr[i].x + dx, y: arr[i].y + dy };
|
|
79
|
-
}
|
|
80
|
-
return out;
|
|
81
|
-
});
|
|
82
|
-
}
|
|
8
|
+
import { Num } from "../values/num.js";
|
|
9
|
+
import { Vec } from "../values/vec.js";
|
|
83
10
|
/** Project `p` into the closed disc of radius `r` centred on `c` (points
|
|
84
11
|
* inside pass through). Use as `argminVec`'s `clampTarget` to fix IK
|
|
85
12
|
* explosion at maximum reach. */
|
|
@@ -4,7 +4,7 @@ type V = {
|
|
|
4
4
|
y: number;
|
|
5
5
|
};
|
|
6
6
|
/** Writable centroid; on write, translates every point by the delta.
|
|
7
|
-
*
|
|
7
|
+
* The Vec-specific group-action reading of `mean`. */
|
|
8
8
|
export declare function rigidTranslate(points: readonly Writable<Vec>[]): Writable<Vec>;
|
|
9
9
|
/** Writable angle from `pivot` to `points[0]`; write rotates every input
|
|
10
10
|
* about `pivot` by (target − current) via its `Pivotal` trait.
|
|
@@ -12,7 +12,7 @@ export declare function rigidTranslate(points: readonly Writable<Vec>[]): Writab
|
|
|
12
12
|
* Trait-generic: Vec rotates position; Pose rotates position AND
|
|
13
13
|
* orientation. Rotation-about-pivot fixes the pivot and preserves radial
|
|
14
14
|
* distances, so scale-about-pivot reads unchanged. `pivot` is reactive
|
|
15
|
-
* (re-read per write); pass `
|
|
15
|
+
* (re-read per write); pass `rigidTranslate(points)` for rotation about
|
|
16
16
|
* the cluster's own centroid. */
|
|
17
17
|
export declare function rotateAbout<T extends {
|
|
18
18
|
x: number;
|
|
@@ -35,22 +35,15 @@ export declare function scaleAbout<T extends {
|
|
|
35
35
|
* point 0's offset, so a per-axis collapse is recoverable (cf.
|
|
36
36
|
* `bboxLens.size`). */
|
|
37
37
|
export declare function scaleAboutXY(points: readonly Writable<Vec>[], pivot: Read<V>): Writable<Vec>;
|
|
38
|
-
|
|
39
|
-
* into three building-block lenses sharing a centroid. */
|
|
40
|
-
export declare function procrustesViaBuildingBlocks(points: readonly Writable<Vec>[]): {
|
|
41
|
-
centroid: Writable<Vec>;
|
|
42
|
-
rotation: Writable<Num>;
|
|
43
|
-
scale: Writable<Num>;
|
|
44
|
-
};
|
|
45
|
-
export declare function bestFitLineLens(points: readonly Writable<Vec>[]): {
|
|
38
|
+
export declare function bestFitLine(points: readonly Writable<Vec>[]): {
|
|
46
39
|
point: Writable<Vec>;
|
|
47
40
|
direction: Writable<Num>;
|
|
48
41
|
};
|
|
49
|
-
export declare function
|
|
42
|
+
export declare function bestFitCircle(points: readonly Writable<Vec>[]): {
|
|
50
43
|
center: Writable<Vec>;
|
|
51
44
|
radius: Writable<Num>;
|
|
52
45
|
};
|
|
53
|
-
export declare function
|
|
46
|
+
export declare function pca(points: readonly Writable<Vec>[]): {
|
|
54
47
|
mean: Writable<Vec>;
|
|
55
48
|
rotation: Writable<Num>;
|
|
56
49
|
majorLength: Writable<Num>;
|
|
@@ -60,5 +53,5 @@ export declare function pcaLens(points: readonly Writable<Vec>[]): {
|
|
|
60
53
|
* preserving their ratios. A `remember` anchored at zero with a signed
|
|
61
54
|
* sum feature: a collapse to zero reinflates the stored ratios, seeded
|
|
62
55
|
* uniform so an all-zero start splits evenly. */
|
|
63
|
-
export declare function
|
|
56
|
+
export declare function total(parts: readonly Writable<Num>[]): Writable<Num>;
|
|
64
57
|
export {};
|