bireactive 0.2.4 → 0.3.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/animation/anim.js +4 -0
- package/dist/coll.d.ts +7 -7
- package/dist/core/cell.d.ts +89 -66
- package/dist/core/cell.js +642 -401
- package/dist/core/index.d.ts +4 -14
- package/dist/core/index.js +4 -14
- package/dist/core/lenses/aggregates.d.ts +1 -1
- package/dist/core/lenses/aggregates.js +4 -3
- package/dist/core/lenses/closed-form-policies.js +6 -6
- package/dist/core/lenses/decompositions.js +3 -3
- package/dist/core/lenses/domain-aggregates.js +5 -5
- package/dist/core/lenses/geometry.d.ts +1 -1
- package/dist/core/lenses/geometry.js +6 -7
- package/dist/core/lenses/memory.d.ts +2 -2
- package/dist/core/lenses/memory.js +3 -3
- package/dist/core/lenses/typed-factor.js +4 -3
- package/dist/core/traits.d.ts +1 -0
- package/dist/core/values/box.js +7 -7
- package/dist/core/values/color.js +5 -5
- package/dist/core/values/field.d.ts +70 -0
- package/dist/core/values/field.js +230 -0
- package/dist/core/values/gpu.d.ts +4 -2
- package/dist/core/values/gpu.js +11 -4
- package/dist/core/values/matrix.js +7 -7
- package/dist/core/values/num.d.ts +1 -1
- package/dist/core/values/num.js +1 -1
- package/dist/core/values/pose.js +4 -4
- package/dist/core/values/range.js +6 -6
- package/dist/core/values/template.d.ts +1 -1
- package/dist/core/values/template.js +2 -1
- package/dist/core/values/transform.js +7 -7
- package/dist/core/values/tri.js +3 -3
- package/dist/core/values/vec.js +8 -12
- package/dist/ext/timeline.js +2 -2
- package/dist/formats/cst.d.ts +127 -0
- package/dist/formats/cst.js +280 -0
- package/dist/formats/edn.d.ts +2 -0
- package/dist/formats/edn.js +301 -0
- package/dist/formats/index.d.ts +6 -0
- package/dist/formats/index.js +8 -0
- package/dist/formats/json.d.ts +2 -0
- package/dist/formats/json.js +332 -0
- package/dist/formats/lens.d.ts +8 -0
- package/dist/formats/lens.js +54 -0
- package/dist/formats/toml.d.ts +2 -0
- package/dist/formats/toml.js +526 -0
- package/dist/formats/yaml.d.ts +2 -0
- package/dist/formats/yaml.js +661 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/learn/data.d.ts +49 -0
- package/dist/learn/data.js +181 -0
- package/dist/learn/index.d.ts +3 -0
- package/dist/learn/index.js +6 -0
- package/dist/learn/lens-net.d.ts +63 -0
- package/dist/learn/lens-net.js +219 -0
- package/dist/learn/mlp.d.ts +77 -0
- package/dist/learn/mlp.js +292 -0
- package/dist/propagators/csp.d.ts +13 -0
- package/dist/propagators/csp.js +52 -0
- package/dist/propagators/flex.d.ts +31 -0
- package/dist/propagators/flex.js +189 -0
- package/dist/propagators/graph.d.ts +73 -0
- package/dist/propagators/graph.js +543 -0
- package/dist/propagators/index.d.ts +8 -6
- package/dist/propagators/index.js +15 -6
- package/dist/propagators/lattice.d.ts +45 -0
- package/dist/propagators/lattice.js +113 -0
- package/dist/propagators/layout.d.ts +1 -27
- package/dist/propagators/layout.js +6 -175
- package/dist/propagators/numeric.d.ts +17 -0
- package/dist/propagators/numeric.js +93 -0
- package/dist/propagators/solver.d.ts +51 -0
- package/dist/propagators/solver.js +175 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/lens.d.ts +121 -0
- package/dist/schema/lens.js +429 -0
- package/dist/shapes/annular-sector.js +4 -4
- package/dist/shapes/button.js +1 -1
- package/dist/shapes/circle.js +1 -1
- package/dist/shapes/handle.js +2 -2
- package/dist/shapes/label.js +1 -1
- package/dist/shapes/layout.js +2 -2
- package/dist/shapes/rect.js +7 -7
- package/dist/shapes/shape.js +8 -8
- package/dist/web/diagram.js +2 -2
- package/package.json +1 -1
- package/dist/propagators/network.d.ts +0 -52
- package/dist/propagators/network.js +0 -185
- package/dist/propagators/propagator.d.ts +0 -12
- package/dist/propagators/propagator.js +0 -16
- package/dist/propagators/range.d.ts +0 -45
- package/dist/propagators/range.js +0 -147
- package/dist/propagators/relations.d.ts +0 -60
- package/dist/propagators/relations.js +0 -343
package/dist/core/index.d.ts
CHANGED
|
@@ -1,33 +1,23 @@
|
|
|
1
|
-
export { batch, Cell, type CellOptions, cachedDerive, cell, derive, effect,
|
|
1
|
+
export { batch, Cell, type CellOptions, cachedDerive, cell, derive, effect, fieldLens, fieldOf, type Init, type Inner, isCell, isLens, isReadonly, lazy, lens, type Network, network, type Read, reader, readNow, SKIP, type Skip, type StatefulBwd, type StatefulLensSpec, setCellWriteHook, settle, transitiveDeps, untracked, type Val, type Writable, type WritableBrand, } from "./cell.js";
|
|
2
2
|
export { bezier2, bezier3 } from "./derived-geometry.js";
|
|
3
3
|
export * from "./lenses/index.js";
|
|
4
4
|
export { each, type Lifecycle } from "./lifecycle.js";
|
|
5
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";
|
|
6
6
|
export { Anchor, Dir } from "./values/anchor.js";
|
|
7
7
|
export { Audio, type AudioClip, audio, stamp as audioStamp } from "./values/audio.js";
|
|
8
|
-
export * as BoolMath from "./values/bool.js";
|
|
9
8
|
export { Bool, bool } from "./values/bool.js";
|
|
10
|
-
export
|
|
11
|
-
export { Box, box } from "./values/box.js";
|
|
9
|
+
export { Box, box, edgeFrom as boxEdgeFrom, expand as boxExpand, union as boxUnion, } from "./values/box.js";
|
|
12
10
|
export { Canvas, canvas, type Raster, stamp as canvasStamp } from "./values/canvas.js";
|
|
13
|
-
export * as ColorMath from "./values/color.js";
|
|
14
11
|
export { Color, rgb, rgba } from "./values/color.js";
|
|
12
|
+
export { type ColorStop, Colour, Field, type FieldVal, field, type Kind as FieldKind, Scalar, Vector, } from "./values/field.js";
|
|
15
13
|
export { Flags, flags } from "./values/flags.js";
|
|
16
14
|
export { blit as gpuBlit, brush as gpuBrush, copy as gpuCopy, newTex as gpuNewTex, Spring, scratch2 as gpuScratch2, type Tex, } from "./values/gpu.js";
|
|
17
|
-
export
|
|
18
|
-
export { Matrix, matrix, transformBox, transformPoint } from "./values/matrix.js";
|
|
19
|
-
export * as NumMath from "./values/num.js";
|
|
15
|
+
export { compose as matrixCompose, Matrix, matrix, toMatrixString, transformBox, transformPoint, } from "./values/matrix.js";
|
|
20
16
|
export { Num, num } from "./values/num.js";
|
|
21
|
-
export * as PoseMath from "./values/pose.js";
|
|
22
17
|
export { Pose, pose } from "./values/pose.js";
|
|
23
|
-
export * as RangeMath from "./values/range.js";
|
|
24
18
|
export { Range, range, span } from "./values/range.js";
|
|
25
|
-
export * as StrMath from "./values/str.js";
|
|
26
19
|
export { Str, str } from "./values/str.js";
|
|
27
20
|
export { type Codec, enumCodec, numCodec, route, type Slot, slot, strCodec, template, tpl, } from "./values/template.js";
|
|
28
|
-
export * as TransformMath from "./values/transform.js";
|
|
29
21
|
export { Transform, type TransformInit, transform } from "./values/transform.js";
|
|
30
|
-
export * as TriMath from "./values/tri.js";
|
|
31
22
|
export { Tri, tri } from "./values/tri.js";
|
|
32
|
-
export * as VecMath from "./values/vec.js";
|
|
33
23
|
export { type PolarPolicy, polar, tangentPoint, Vec, vec } from "./values/vec.js";
|
package/dist/core/index.js
CHANGED
|
@@ -1,33 +1,23 @@
|
|
|
1
|
-
export { batch, Cell, cachedDerive, cell, derive, effect,
|
|
1
|
+
export { batch, Cell, cachedDerive, cell, derive, effect, fieldLens, fieldOf, isCell, isLens, isReadonly, lazy, lens, network, reader, readNow, SKIP, setCellWriteHook, settle, transitiveDeps, untracked, } from "./cell.js";
|
|
2
2
|
export { bezier2, bezier3 } from "./derived-geometry.js";
|
|
3
3
|
export * from "./lenses/index.js";
|
|
4
4
|
export { each } from "./lifecycle.js";
|
|
5
5
|
export { requireEquals, requireLerp, requireLinear, requireMetric, requirePack, requirePivotal, } from "./traits.js";
|
|
6
6
|
export { Anchor, Dir } from "./values/anchor.js";
|
|
7
7
|
export { Audio, audio, stamp as audioStamp } from "./values/audio.js";
|
|
8
|
-
export * as BoolMath from "./values/bool.js";
|
|
9
8
|
export { Bool, bool } from "./values/bool.js";
|
|
10
|
-
export
|
|
11
|
-
export { Box, box } from "./values/box.js";
|
|
9
|
+
export { Box, box, edgeFrom as boxEdgeFrom, expand as boxExpand, union as boxUnion, } from "./values/box.js";
|
|
12
10
|
export { Canvas, canvas, stamp as canvasStamp } from "./values/canvas.js";
|
|
13
|
-
export * as ColorMath from "./values/color.js";
|
|
14
11
|
export { Color, rgb, rgba } from "./values/color.js";
|
|
12
|
+
export { Colour, Field, field, Scalar, Vector, } from "./values/field.js";
|
|
15
13
|
export { Flags, flags } from "./values/flags.js";
|
|
16
14
|
export { blit as gpuBlit, brush as gpuBrush, copy as gpuCopy, newTex as gpuNewTex, Spring, scratch2 as gpuScratch2, } from "./values/gpu.js";
|
|
17
|
-
export
|
|
18
|
-
export { Matrix, matrix, transformBox, transformPoint } from "./values/matrix.js";
|
|
19
|
-
export * as NumMath from "./values/num.js";
|
|
15
|
+
export { compose as matrixCompose, Matrix, matrix, toMatrixString, transformBox, transformPoint, } from "./values/matrix.js";
|
|
20
16
|
export { Num, num } from "./values/num.js";
|
|
21
|
-
export * as PoseMath from "./values/pose.js";
|
|
22
17
|
export { Pose, pose } from "./values/pose.js";
|
|
23
|
-
export * as RangeMath from "./values/range.js";
|
|
24
18
|
export { Range, range, span } from "./values/range.js";
|
|
25
|
-
export * as StrMath from "./values/str.js";
|
|
26
19
|
export { Str, str } from "./values/str.js";
|
|
27
20
|
export { enumCodec, numCodec, route, slot, strCodec, template, tpl, } from "./values/template.js";
|
|
28
|
-
export * as TransformMath from "./values/transform.js";
|
|
29
21
|
export { Transform, transform } from "./values/transform.js";
|
|
30
|
-
export * as TriMath from "./values/tri.js";
|
|
31
22
|
export { Tri, tri } from "./values/tri.js";
|
|
32
|
-
export * as VecMath from "./values/vec.js";
|
|
33
23
|
export { polar, tangentPoint, Vec, vec } from "./values/vec.js";
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// All route through the engine's N-input lens path. Stateless-bwd
|
|
6
6
|
// (`(target) => updates`) skips the peek loop on the hot path;
|
|
7
7
|
// stateful-bwd (`(target, vals) => updates`) reads the scratch.
|
|
8
|
+
import { SKIP } from "../cell.js";
|
|
8
9
|
import { Num } from "../values/num.js";
|
|
9
10
|
import { Vec } from "../values/vec.js";
|
|
10
11
|
/** Project `p` into the closed disc of radius `r` centred on `c` (points
|
|
@@ -51,7 +52,7 @@ export function argminNum(inputs, forward, weights, opts = {}) {
|
|
|
51
52
|
const k = dy / denom;
|
|
52
53
|
for (let i = 0; i < n; i++) {
|
|
53
54
|
if (weights[i] === 0) {
|
|
54
|
-
out[i] =
|
|
55
|
+
out[i] = SKIP;
|
|
55
56
|
}
|
|
56
57
|
else {
|
|
57
58
|
out[i] = xs[i] + weights[i] * J[i] * k;
|
|
@@ -103,7 +104,7 @@ export function argminVec(inputs, forward, weights, opts = {}) {
|
|
|
103
104
|
if (Math.abs(det) < 1e-14) {
|
|
104
105
|
// Singular; leave inputs unchanged.
|
|
105
106
|
for (let i = 0; i < n; i++)
|
|
106
|
-
out[i] =
|
|
107
|
+
out[i] = SKIP;
|
|
107
108
|
return out;
|
|
108
109
|
}
|
|
109
110
|
const invA = c / det;
|
|
@@ -114,7 +115,7 @@ export function argminVec(inputs, forward, weights, opts = {}) {
|
|
|
114
115
|
for (let i = 0; i < n; i++) {
|
|
115
116
|
const w = weights[i];
|
|
116
117
|
if (w === 0) {
|
|
117
|
-
out[i] =
|
|
118
|
+
out[i] = SKIP;
|
|
118
119
|
}
|
|
119
120
|
else {
|
|
120
121
|
out[i] = xs[i] + w * (Jx[i] * kx + Jy[i] * ky);
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// (bestFitLine, bestFitCircle, pca, total). All exact, idempotent,
|
|
11
11
|
// cross-channel invariant by construction, on the same `Cls.lens`
|
|
12
12
|
// machinery — no engine changes.
|
|
13
|
-
import { mean, Num, Vec, } from "../index.js";
|
|
13
|
+
import { mean, Num, SKIP, Vec, } from "../index.js";
|
|
14
14
|
import { continuous, remember } from "./memory.js";
|
|
15
15
|
// Pivotal trait lookup via the value class's `static traits.pivotal` slot.
|
|
16
16
|
// biome-ignore lint/suspicious/noExplicitAny: dynamic trait lookup
|
|
@@ -50,7 +50,7 @@ export function rotateAbout(points, pivot) {
|
|
|
50
50
|
const rx0 = vals[0].x - p.x;
|
|
51
51
|
const ry0 = vals[0].y - p.y;
|
|
52
52
|
if (rx0 * rx0 + ry0 * ry0 < 1e-24) {
|
|
53
|
-
return vals.map(() =>
|
|
53
|
+
return vals.map(() => SKIP);
|
|
54
54
|
}
|
|
55
55
|
const oldθ = Math.atan2(ry0, rx0);
|
|
56
56
|
const dθ = target - oldθ;
|
|
@@ -96,11 +96,11 @@ export function scaleAbout(points, pivot) {
|
|
|
96
96
|
// re-projects to the current radius and is absorbed (sources put).
|
|
97
97
|
const rNow = Math.hypot(vals[0].x - p.x, vals[0].y - p.y);
|
|
98
98
|
if (Math.abs(target) === rNow)
|
|
99
|
-
return { updates: vals.map(() =>
|
|
99
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
100
100
|
const d0 = c.devs[0];
|
|
101
101
|
const r0 = Math.hypot(d0.x, d0.y);
|
|
102
102
|
if (r0 < 1e-12)
|
|
103
|
-
return { updates: vals.map(() =>
|
|
103
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
104
104
|
const k = target / r0;
|
|
105
105
|
const out = vals.map((v, i) => ({
|
|
106
106
|
...v,
|
|
@@ -299,7 +299,7 @@ export function pca(points) {
|
|
|
299
299
|
const rotation = Num.lens(points, (vals) => decompose(vals)?.θ ?? 0, (target, vals) => {
|
|
300
300
|
const d = decompose(vals);
|
|
301
301
|
if (!d)
|
|
302
|
-
return vals.map(() =>
|
|
302
|
+
return vals.map(() => SKIP);
|
|
303
303
|
const dθ = target - d.θ;
|
|
304
304
|
const cos = Math.cos(dθ);
|
|
305
305
|
const sin = Math.sin(dθ);
|
|
@@ -382,7 +382,7 @@ export function pca(points) {
|
|
|
382
382
|
// Lossy magnitude view: a same-magnitude target re-projects to
|
|
383
383
|
// the current axis length and is absorbed (cluster left put).
|
|
384
384
|
if (Math.abs(target) === c.lenThis)
|
|
385
|
-
return { updates: vals.map(() =>
|
|
385
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
386
386
|
// Non-degenerate fast path: scale current cluster along axis.
|
|
387
387
|
const k = target / c.lenThis;
|
|
388
388
|
return { updates: scaleAlongAxis(vals, d.cx, d.cy, c.uX, c.uY, k), complement: c };
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// about the centroid), so cross-channel invariance is EXACT and one
|
|
7
7
|
// write lands in O(K). For the generic numerical N→M escape hatch (when
|
|
8
8
|
// no closed form fits) see `factor` in `typed-factor.ts`.
|
|
9
|
-
import { Num, Vec } from "../index.js";
|
|
9
|
+
import { Num, SKIP, Vec } from "../index.js";
|
|
10
10
|
// meanDiff — M=2 isomorphism baseline.
|
|
11
11
|
//
|
|
12
12
|
// (a, b) → ((a+b)/2, a−b). Square full-rank linear lens; bwd is the
|
|
@@ -84,7 +84,7 @@ export function procrustes(points) {
|
|
|
84
84
|
const ry0 = vals[0].y - cy;
|
|
85
85
|
if (rx0 * rx0 + ry0 * ry0 < 1e-24) {
|
|
86
86
|
// Collapsed cluster; no angle to rotate from.
|
|
87
|
-
return vals.map(() =>
|
|
87
|
+
return vals.map(() => SKIP);
|
|
88
88
|
}
|
|
89
89
|
const oldθ = Math.atan2(ry0, rx0);
|
|
90
90
|
const dθ = target - oldθ;
|
|
@@ -130,7 +130,7 @@ export function procrustes(points) {
|
|
|
130
130
|
const d0 = c.devs[0];
|
|
131
131
|
const r0 = Math.hypot(d0.x, d0.y);
|
|
132
132
|
if (r0 < 1e-12)
|
|
133
|
-
return { updates: vals.map(() =>
|
|
133
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
134
134
|
const k = target / r0;
|
|
135
135
|
const out = c.devs.map(d => ({ x: cen.x + k * d.x, y: cen.y + k * d.y }));
|
|
136
136
|
return { updates: out, complement: c };
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// (2) Bezier gestalt handles ({start, end, startTangent, endTangent}).
|
|
7
7
|
// (3) Time-series ({mean, slope}) over (i, value) samples.
|
|
8
8
|
// All exact, idempotent, cross-channel invariant by construction.
|
|
9
|
-
import { Num, reader, Vec, } from "../index.js";
|
|
9
|
+
import { Num, reader, SKIP, Vec, } from "../index.js";
|
|
10
10
|
import { remember } from "./memory.js";
|
|
11
11
|
// Generic Linear-trait aggregates.
|
|
12
12
|
//
|
|
@@ -107,9 +107,9 @@ export function mix(weights, branches) {
|
|
|
107
107
|
const { w, sumSq } = readW();
|
|
108
108
|
const delta = lin.sub(target, combine(vals, w));
|
|
109
109
|
if (sumSq < 1e-12)
|
|
110
|
-
return vals.map(() =>
|
|
110
|
+
return vals.map(() => SKIP);
|
|
111
111
|
const inv = 1 / sumSq;
|
|
112
|
-
return vals.map((v, i) => w[i] === 0 ?
|
|
112
|
+
return vals.map((v, i) => w[i] === 0 ? SKIP : lin.add(v, lin.scale(delta, w[i] * inv)));
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
115
|
/** Two-branch router (mix simplex *vertex*): reads the live branch, writes
|
|
@@ -187,8 +187,8 @@ export function bezierGestalt(p0, p1, p2, p3) {
|
|
|
187
187
|
const dy = target.y - vals[1].y;
|
|
188
188
|
return [{ x: vals[0].x + dx, y: vals[0].y + dy }, target];
|
|
189
189
|
});
|
|
190
|
-
const startTangent = Vec.lens([p0, p1], (vals) => ({ x: vals[1].x - vals[0].x, y: vals[1].y - vals[0].y }), (target, vals) => [
|
|
191
|
-
const endTangent = Vec.lens([p2, p3], (vals) => ({ x: vals[1].x - vals[0].x, y: vals[1].y - vals[0].y }), (target, vals) => [{ x: vals[1].x - target.x, y: vals[1].y - target.y },
|
|
190
|
+
const startTangent = Vec.lens([p0, p1], (vals) => ({ x: vals[1].x - vals[0].x, y: vals[1].y - vals[0].y }), (target, vals) => [SKIP, { x: vals[0].x + target.x, y: vals[0].y + target.y }]);
|
|
191
|
+
const endTangent = Vec.lens([p2, p3], (vals) => ({ x: vals[1].x - vals[0].x, y: vals[1].y - vals[0].y }), (target, vals) => [{ x: vals[1].x - target.x, y: vals[1].y - target.y }, SKIP]);
|
|
192
192
|
return { start, end, startTangent, endTangent };
|
|
193
193
|
}
|
|
194
194
|
// Time-series aggregates.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// geometry.ts — geometric lens building blocks over the N-input
|
|
2
2
|
// `Cls.lens` / `Cls.derive` forms. All are a few lines on top of the engine.
|
|
3
|
+
import { SKIP } from "../cell.js";
|
|
3
4
|
import { Num } from "../values/num.js";
|
|
4
5
|
import { Vec } from "../values/vec.js";
|
|
5
6
|
import { rotateAbout } from "./closed-form-policies.js";
|
|
@@ -36,7 +37,7 @@ export function reflection(point, axisStart, axisEnd) {
|
|
|
36
37
|
const projY = a.y + t * dy;
|
|
37
38
|
return { x: 2 * projX - p.x, y: 2 * projY - p.y };
|
|
38
39
|
};
|
|
39
|
-
return Vec.lens([point, axisStart, axisEnd], vals => reflect(vals[0], vals[1], vals[2]), (target, vals) => [reflect(target, vals[1], vals[2]),
|
|
40
|
+
return Vec.lens([point, axisStart, axisEnd], vals => reflect(vals[0], vals[1], vals[2]), (target, vals) => [reflect(target, vals[1], vals[2]), SKIP, SKIP]);
|
|
40
41
|
}
|
|
41
42
|
/** Lerp between two Vecs at parameter `t`. Writing the interpolated point
|
|
42
43
|
* shifts both endpoints rigidly (preserving t). */
|
|
@@ -48,7 +49,7 @@ export function vecLerp(a, b, t) {
|
|
|
48
49
|
const [av, bv, tv] = vals;
|
|
49
50
|
const dx = target.x - (av.x + (bv.x - av.x) * tv);
|
|
50
51
|
const dy = target.y - (av.y + (bv.y - av.y) * tv);
|
|
51
|
-
return [{ x: av.x + dx, y: av.y + dy }, { x: bv.x + dx, y: bv.y + dy },
|
|
52
|
+
return [{ x: av.x + dx, y: av.y + dy }, { x: bv.x + dx, y: bv.y + dy }, SKIP];
|
|
52
53
|
});
|
|
53
54
|
}
|
|
54
55
|
/** Sum of two nums; writing the sum splits the delta equally between
|
|
@@ -77,23 +78,21 @@ export function clampedMean(parents, lo, hi) {
|
|
|
77
78
|
const n = parents.length;
|
|
78
79
|
const inv = 1 / n;
|
|
79
80
|
return Num.lens(parents, vals => {
|
|
80
|
-
const arr = vals;
|
|
81
81
|
let s = 0;
|
|
82
82
|
for (let i = 0; i < n; i++)
|
|
83
|
-
s +=
|
|
83
|
+
s += vals[i];
|
|
84
84
|
const m = s * inv;
|
|
85
85
|
return m < lo ? lo : m > hi ? hi : m;
|
|
86
86
|
}, (target, vals) => {
|
|
87
|
-
const arr = vals;
|
|
88
87
|
const clamped = target < lo ? lo : target > hi ? hi : target;
|
|
89
88
|
let s = 0;
|
|
90
89
|
for (let i = 0; i < n; i++)
|
|
91
|
-
s +=
|
|
90
|
+
s += vals[i];
|
|
92
91
|
const cur = s * inv;
|
|
93
92
|
const delta = clamped - cur;
|
|
94
93
|
const out = new Array(n);
|
|
95
94
|
for (let i = 0; i < n; i++)
|
|
96
|
-
out[i] =
|
|
95
|
+
out[i] = vals[i] + delta;
|
|
97
96
|
return out;
|
|
98
97
|
});
|
|
99
98
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Cell, Num, type Traits, type Writable } from "../index.js";
|
|
1
|
+
import { type Cell, Num, type Skip, type Traits, type Writable } from "../index.js";
|
|
2
2
|
/** Options for {@link remember}. `anchor` is the fixed point sources scale
|
|
3
3
|
* about (a pivot, or the live centroid); `feature` is the writable scalar
|
|
4
4
|
* (a radius, mean distance, or sum). */
|
|
@@ -38,7 +38,7 @@ export interface ContinuousOpts<T> {
|
|
|
38
38
|
};
|
|
39
39
|
/** Realize `target` (already unwrapped, absolute) onto the sources,
|
|
40
40
|
* given the `current` unwrapped reading (for a delta). */
|
|
41
|
-
apply: (target: number, vals: readonly T[], current: number) => readonly (T |
|
|
41
|
+
apply: (target: number, vals: readonly T[], current: number) => readonly (T | Skip)[];
|
|
42
42
|
}
|
|
43
43
|
/** Continuous (winding-aware) lens over a cyclic reading. The complement
|
|
44
44
|
* tracks the last emitted value and unwraps each raw reading to the
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// unwraps the raw reading to the nearest sheet, so the
|
|
16
16
|
// view never tears at a branch cut. Covers the eigenvector
|
|
17
17
|
// angle of bestFitLine; the primitive behind winding.
|
|
18
|
-
import { Num } from "../index.js";
|
|
18
|
+
import { Num, SKIP } from "../index.js";
|
|
19
19
|
/** Scalar shape-memory lens. Reads `feature(sources)`; writing it scales
|
|
20
20
|
* the cluster about `anchor` so the new feature matches, reinflating the
|
|
21
21
|
* remembered shape when the cluster has collapsed onto the anchor. The
|
|
@@ -59,7 +59,7 @@ export function remember(sources, opts) {
|
|
|
59
59
|
// Magnitude is lossy (|−f| = f): a same-magnitude target re-projects
|
|
60
60
|
// to the current feature, so the cluster is left put.
|
|
61
61
|
if (magnitude && Math.abs(target) === f) {
|
|
62
|
-
return { updates: vals.map(() =>
|
|
62
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
63
63
|
}
|
|
64
64
|
if (f > eps) {
|
|
65
65
|
const k = target / f;
|
|
@@ -94,7 +94,7 @@ export function continuous(sources, opts) {
|
|
|
94
94
|
bwd: (target, vals, c) => {
|
|
95
95
|
const r = raw(vals);
|
|
96
96
|
if (!r.defined)
|
|
97
|
-
return { updates: vals.map(() =>
|
|
97
|
+
return { updates: vals.map(() => SKIP), complement: { prev: target } };
|
|
98
98
|
const current = unwrap(r.value, c.prev);
|
|
99
99
|
return { updates: apply(target, vals, current), complement: { prev: target } };
|
|
100
100
|
},
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// centroid.value = { x: 100, y: 50 }; // typed
|
|
15
15
|
//
|
|
16
16
|
// `bundle()` is the 1→M case: `factor()` over a single typed source.
|
|
17
|
+
import { SKIP } from "../index.js";
|
|
17
18
|
import { solveSPD } from "../linalg.js";
|
|
18
19
|
function getPack(cell) {
|
|
19
20
|
const ctor = cell.constructor;
|
|
@@ -163,7 +164,7 @@ export function factor(inputs, outputs, opts = {}) {
|
|
|
163
164
|
}
|
|
164
165
|
// 6. Solve A · k = δy in place (LDLᵀ; `dy` is overwritten with k).
|
|
165
166
|
if (!solveSPD(A, dy, M)) {
|
|
166
|
-
return vals.map(() =>
|
|
167
|
+
return vals.map(() => SKIP);
|
|
167
168
|
}
|
|
168
169
|
// 7. δx = W J^T k, applied to flatIn → produces new flat input vector.
|
|
169
170
|
// Then unpack per-input to typed updates.
|
|
@@ -187,7 +188,7 @@ export function factor(inputs, outputs, opts = {}) {
|
|
|
187
188
|
}
|
|
188
189
|
updates[k] = anyChange
|
|
189
190
|
? inputPacks[k].write(flatIn, baseOff)
|
|
190
|
-
:
|
|
191
|
+
: SKIP;
|
|
191
192
|
}
|
|
192
193
|
return updates;
|
|
193
194
|
};
|
|
@@ -211,7 +212,7 @@ export function factor(inputs, outputs, opts = {}) {
|
|
|
211
212
|
for (let it = 0; it < maxIters; it++) {
|
|
212
213
|
const updates = computeBwd(idx, target, cur);
|
|
213
214
|
for (let i = 0; i < cur.length; i++) {
|
|
214
|
-
if (updates[i] !==
|
|
215
|
+
if (updates[i] !== SKIP)
|
|
215
216
|
cur[i] = updates[i];
|
|
216
217
|
}
|
|
217
218
|
outPack.read(spec.fwd(cur), currentBuf, 0);
|
package/dist/core/traits.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export type TraitKey = keyof TraitDict<unknown>;
|
|
|
49
49
|
* function spring<T>(sig: Traits<T, "linear" | "metric">, target: Val<T>)
|
|
50
50
|
* function tween<T>(sig: Traits<T, "lerp">, target: T, dur: Val<number>) */
|
|
51
51
|
export type Traits<T, K extends TraitKey = never> = {
|
|
52
|
+
/** @internal Phantom slot; never accessed at runtime. */
|
|
52
53
|
readonly _t: {
|
|
53
54
|
[P in K]-?: NonNullable<TraitDict<T>[P]>;
|
|
54
55
|
} & TraitDict<T>;
|
package/dist/core/values/box.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Invertibles (`add`, `sub`, `scale`, `expand`) return `: this` and ride
|
|
4
4
|
// on `Cell#lens(fwd, bwd)`. Chained calls compose into a lens chain.
|
|
5
5
|
import { tween } from "../../animation/index.js";
|
|
6
|
-
import { Cell, cachedDerive,
|
|
6
|
+
import { Cell, cachedDerive, fieldLens, isReadonly, lazy, reader, readNow, SKIP, } from "../cell.js";
|
|
7
7
|
import { Bool } from "./bool.js";
|
|
8
8
|
import { Num, num } from "./num.js";
|
|
9
9
|
import { Vec } from "./vec.js";
|
|
@@ -138,24 +138,24 @@ export class Box extends Cell {
|
|
|
138
138
|
return mk([this, p], vals => contains(vals[0], vals[1]), (target, vals) => {
|
|
139
139
|
const [b, v] = vals;
|
|
140
140
|
if (contains(b, v) === target)
|
|
141
|
-
return [
|
|
142
|
-
return [
|
|
141
|
+
return [SKIP, SKIP];
|
|
142
|
+
return [SKIP, target ? clampToBox(v, b) : ejectFromBox(v, b)];
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
return Bool.derive(() => contains(this.value, readNow(p)));
|
|
147
147
|
}
|
|
148
148
|
get x() {
|
|
149
|
-
return
|
|
149
|
+
return fieldLens(this, "x", Num);
|
|
150
150
|
}
|
|
151
151
|
get y() {
|
|
152
|
-
return
|
|
152
|
+
return fieldLens(this, "y", Num);
|
|
153
153
|
}
|
|
154
154
|
get w() {
|
|
155
|
-
return
|
|
155
|
+
return fieldLens(this, "w", Num);
|
|
156
156
|
}
|
|
157
157
|
get h() {
|
|
158
|
-
return
|
|
158
|
+
return fieldLens(this, "h", Num);
|
|
159
159
|
}
|
|
160
160
|
get area() {
|
|
161
161
|
return cachedDerive(this, "area", Num, b => b.w * b.h);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Invertibles (`add`, `sub`, `scale`) return `: this` and ride on
|
|
4
4
|
// `Cell#lens(fwd, bwd)`. Chained calls compose into a lens chain.
|
|
5
5
|
import { tween } from "../../animation/index.js";
|
|
6
|
-
import { Cell, cachedDerive, derive,
|
|
6
|
+
import { Cell, cachedDerive, derive, fieldLens, lazy, reader, readNow, } from "../cell.js";
|
|
7
7
|
import { Num, num } from "./num.js";
|
|
8
8
|
export const add = (a, b) => ({ r: a.r + b.r, g: a.g + b.g, b: a.b + b.b, a: a.a + b.a });
|
|
9
9
|
export const sub = (a, b) => ({ r: a.r - b.r, g: a.g - b.g, b: a.b - b.b, a: a.a - b.a });
|
|
@@ -55,16 +55,16 @@ export class Color extends Cell {
|
|
|
55
55
|
return Color.derive(() => lerp(this.value, readNow(b), readNow(t)));
|
|
56
56
|
}
|
|
57
57
|
get r() {
|
|
58
|
-
return
|
|
58
|
+
return fieldLens(this, "r", Num);
|
|
59
59
|
}
|
|
60
60
|
get g() {
|
|
61
|
-
return
|
|
61
|
+
return fieldLens(this, "g", Num);
|
|
62
62
|
}
|
|
63
63
|
get b() {
|
|
64
|
-
return
|
|
64
|
+
return fieldLens(this, "b", Num);
|
|
65
65
|
}
|
|
66
66
|
get a() {
|
|
67
|
-
return
|
|
67
|
+
return fieldLens(this, "a", Num);
|
|
68
68
|
}
|
|
69
69
|
get luminance() {
|
|
70
70
|
return cachedDerive(this, "luminance", Num, c => 0.299 * c.r + 0.587 * c.g + 0.114 * c.b);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Cell, type Read, type Val } from "../cell.js";
|
|
2
|
+
import type { Pack } from "../traits.js";
|
|
3
|
+
import { Canvas } from "./canvas.js";
|
|
4
|
+
/** Field cell value: a GPU handle. The graph compares `epoch`. */
|
|
5
|
+
export interface FieldVal {
|
|
6
|
+
readonly tex: WebGLTexture;
|
|
7
|
+
readonly w: number;
|
|
8
|
+
readonly h: number;
|
|
9
|
+
readonly epoch: number;
|
|
10
|
+
}
|
|
11
|
+
type Ctor<T> = new (...args: never[]) => Cell<T>;
|
|
12
|
+
/** Texel encoding: channel count, the flat-buffer codec, and the boundary
|
|
13
|
+
* cell class that reductions return. */
|
|
14
|
+
export interface Kind<T> {
|
|
15
|
+
readonly dim: 1 | 2 | 4;
|
|
16
|
+
readonly pack: Pack<T>;
|
|
17
|
+
readonly cls: Ctor<T>;
|
|
18
|
+
}
|
|
19
|
+
/** Scalar field (1 channel) — heatmaps, SDFs, density, height. */
|
|
20
|
+
export declare const Scalar: Kind<number>;
|
|
21
|
+
/** Vector field (2 channels) — flow, gradient, displacement, RD chemicals. */
|
|
22
|
+
export declare const Vector: Kind<{
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
}>;
|
|
26
|
+
/** Colour field (4 channels) — i.e. a Canvas. */
|
|
27
|
+
export declare const Colour: Kind<{
|
|
28
|
+
r: number;
|
|
29
|
+
g: number;
|
|
30
|
+
b: number;
|
|
31
|
+
a: number;
|
|
32
|
+
}>;
|
|
33
|
+
/** A colormap stop: a field value mapped to an RGB triple (0–1). */
|
|
34
|
+
export type ColorStop = readonly [number, readonly [number, number, number]];
|
|
35
|
+
export declare class Field<T> extends Cell<FieldVal> {
|
|
36
|
+
readonly kind: Kind<T>;
|
|
37
|
+
static traits: {
|
|
38
|
+
equals: (a: FieldVal, b: FieldVal) => boolean;
|
|
39
|
+
};
|
|
40
|
+
readonly _t: typeof Field.traits;
|
|
41
|
+
/** Feedback-safe ping-pong pair for `evolve`/`splat`, lazily allocated. */
|
|
42
|
+
private io;
|
|
43
|
+
constructor(kind: Kind<T>, v?: FieldVal);
|
|
44
|
+
private pingTex;
|
|
45
|
+
/** Step the field by `steps` GPU passes of `frag` (which samples the current
|
|
46
|
+
* field as `u_src`; `u_texel` = 1/size is provided). One value is committed
|
|
47
|
+
* after the substeps, so the reactive graph sees a single new epoch/frame. */
|
|
48
|
+
evolve(frag: string, uniforms?: Record<string, number | readonly number[]>, steps?: number): void;
|
|
49
|
+
/** Stamp a Gaussian disc of `value` at data pixel `(x, y)`, radius `r`. The
|
|
50
|
+
* raster interaction primitive — seed a sim, inject, paint density. */
|
|
51
|
+
splat(x: number, y: number, r: number, value: T, strength?: number): void;
|
|
52
|
+
/** Whole-field mean as a read-only `T` cell. Reactive: recomputes on every
|
|
53
|
+
* new epoch, propagates only when the value moves. One 1×1 GPU readback. */
|
|
54
|
+
mean(): Read<T>;
|
|
55
|
+
/** Mean over a sub-rectangle (data pixels, reactive `box`) as a read-only
|
|
56
|
+
* `T` cell — the field's "density of this region" observation. */
|
|
57
|
+
regionMean(box: Val<{
|
|
58
|
+
x: number;
|
|
59
|
+
y: number;
|
|
60
|
+
w: number;
|
|
61
|
+
h: number;
|
|
62
|
+
}>): Read<T>;
|
|
63
|
+
/** Render `channel` through a colormap to a read-only `Canvas`. Reactive:
|
|
64
|
+
* re-renders on every new epoch, so rendering is itself a reactive edge. */
|
|
65
|
+
colormap(channel: number, stops: readonly ColorStop[]): Canvas;
|
|
66
|
+
}
|
|
67
|
+
/** Writable `Field<T>` of size `w×h`. `painter` fills each texel (returns a
|
|
68
|
+
* `T`); omit for an all-zero field. Linear-filtered for continuous sampling. */
|
|
69
|
+
export declare function field<T>(kind: Kind<T>, w: number, h: number, painter?: (x: number, y: number) => T): Field<T>;
|
|
70
|
+
export {};
|