bireactive 0.3.1 → 0.3.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.
Files changed (89) hide show
  1. package/README.md +14 -7
  2. package/dist/core/_counts.js +5 -12
  3. package/dist/core/cell.d.ts +3 -3
  4. package/dist/core/cell.js +6 -7
  5. package/dist/core/derived-geometry.js +4 -7
  6. package/dist/core/index.d.ts +3 -1
  7. package/dist/core/index.js +3 -1
  8. package/dist/core/lenses/aggregates.d.ts +42 -52
  9. package/dist/core/lenses/aggregates.js +225 -116
  10. package/dist/core/lenses/geometry.d.ts +22 -4
  11. package/dist/core/lenses/geometry.js +59 -27
  12. package/dist/core/lenses/index.d.ts +5 -6
  13. package/dist/core/lenses/index.js +5 -6
  14. package/dist/core/lenses/memory.js +4 -17
  15. package/dist/core/lenses/numerical.d.ts +100 -0
  16. package/dist/core/lenses/{typed-factor.js → numerical.js} +136 -34
  17. package/dist/core/lenses/point-cloud.d.ts +67 -0
  18. package/dist/core/lenses/{closed-form-policies.js → point-cloud.js} +218 -81
  19. package/dist/core/lenses/snap.d.ts +1 -1
  20. package/dist/core/lenses/snap.js +3 -10
  21. package/dist/core/lenses/text.d.ts +40 -0
  22. package/dist/core/lenses/text.js +202 -0
  23. package/dist/core/lifecycle.js +3 -6
  24. package/dist/core/linalg.js +5 -11
  25. package/dist/core/optic.js +10 -15
  26. package/dist/core/optics.js +4 -8
  27. package/dist/core/store.d.ts +1 -2
  28. package/dist/core/store.js +7 -15
  29. package/dist/core/traits.d.ts +4 -7
  30. package/dist/core/traits.js +8 -12
  31. package/dist/core/values/anchor.js +0 -4
  32. package/dist/core/values/arr.d.ts +110 -0
  33. package/dist/core/values/arr.js +336 -0
  34. package/dist/core/values/audio.d.ts +8 -9
  35. package/dist/core/values/audio.js +7 -23
  36. package/dist/core/values/bool.d.ts +11 -11
  37. package/dist/core/values/bool.js +12 -22
  38. package/dist/core/values/box.d.ts +15 -20
  39. package/dist/core/values/box.js +20 -33
  40. package/dist/core/values/canvas.d.ts +18 -25
  41. package/dist/core/values/canvas.js +17 -48
  42. package/dist/core/values/color.d.ts +5 -7
  43. package/dist/core/values/color.js +5 -11
  44. package/dist/core/values/field.d.ts +6 -7
  45. package/dist/core/values/field.js +10 -35
  46. package/dist/core/values/flags.d.ts +1 -2
  47. package/dist/core/values/flags.js +1 -17
  48. package/dist/core/values/gpu.d.ts +6 -10
  49. package/dist/core/values/gpu.js +8 -22
  50. package/dist/core/values/matrix.d.ts +2 -4
  51. package/dist/core/values/matrix.js +2 -12
  52. package/dist/core/values/num.d.ts +19 -28
  53. package/dist/core/values/num.js +23 -41
  54. package/dist/core/values/pose.d.ts +2 -4
  55. package/dist/core/values/pose.js +3 -12
  56. package/dist/core/values/range.d.ts +18 -26
  57. package/dist/core/values/range.js +22 -39
  58. package/dist/core/values/reg/ambiguity.d.ts +8 -0
  59. package/dist/core/values/reg/ambiguity.js +131 -0
  60. package/dist/core/values/reg/engine.d.ts +91 -0
  61. package/dist/core/values/reg/engine.js +373 -0
  62. package/dist/core/values/reg/nfa.d.ts +42 -0
  63. package/dist/core/values/reg/nfa.js +391 -0
  64. package/dist/core/values/reg/regex.d.ts +7 -0
  65. package/dist/core/values/reg/regex.js +318 -0
  66. package/dist/core/values/reg/types.d.ts +60 -0
  67. package/dist/core/values/reg/types.js +3 -0
  68. package/dist/core/values/reg.d.ts +250 -0
  69. package/dist/core/values/reg.js +649 -0
  70. package/dist/core/values/str.d.ts +16 -60
  71. package/dist/core/values/str.js +133 -315
  72. package/dist/core/values/template.js +1 -24
  73. package/dist/core/values/transform.d.ts +3 -5
  74. package/dist/core/values/transform.js +3 -12
  75. package/dist/core/values/tri.d.ts +9 -10
  76. package/dist/core/values/tri.js +9 -15
  77. package/dist/core/values/vec.d.ts +9 -24
  78. package/dist/core/values/vec.js +9 -64
  79. package/dist/index.d.ts +0 -11
  80. package/dist/index.js +1 -11
  81. package/package.json +6 -7
  82. package/dist/coll.d.ts +0 -74
  83. package/dist/coll.js +0 -210
  84. package/dist/core/lenses/closed-form-policies.d.ts +0 -57
  85. package/dist/core/lenses/decompositions.d.ts +0 -14
  86. package/dist/core/lenses/decompositions.js +0 -224
  87. package/dist/core/lenses/domain-aggregates.d.ts +0 -42
  88. package/dist/core/lenses/domain-aggregates.js +0 -245
  89. package/dist/core/lenses/typed-factor.d.ts +0 -40
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # bi-reactive
2
2
 
3
- [npm](https://www.npmjs.com/package/bireactive) · [GitHub](https://github.com/OrionReed/bireactive) · [site](https://orionreed.github.io/bireactive/) · [API](https://orionreed.github.io/bireactive/api/)
3
+ [NPM](https://www.npmjs.com/package/bireactive) · [GitHub](https://github.com/OrionReed/bireactive) · [Demos](https://orionreed.github.io/bireactive/) · [API](https://orionreed.github.io/bireactive/api/)
4
4
 
5
5
  A signals-like bidirectional reactive programming system where edges can go both ways. Forward and backward propagation are handled by the engine, with the same set of caveats as regular reactive programming.
6
6
 
@@ -10,9 +10,9 @@ A signals-like bidirectional reactive programming system where edges can go both
10
10
  npm install bireactive
11
11
  ```
12
12
 
13
- Runtime dependencies [`temml`](https://temml.org) (for `tex`) and
13
+ Runtime dependencies [`temml`](https://temml.org) (for `tex`), [`Automerge`](https://automerge.org) and
14
14
  [`prism-esm`](https://github.com/orionhealthotago/prism-esm) (for `code`) are
15
- installed automatically. They may be split into separate packages later so the
15
+ installed automatically. These will be split into separate packages later so the
16
16
  core stays dependency-free.
17
17
 
18
18
  ## Sketch
@@ -61,20 +61,27 @@ inside.value = true; // assert membership…
61
61
  q.value; // { x: 100, y: 50 } — q snaps to the nearest in-box point
62
62
  ```
63
63
 
64
+ ## Documentation
65
+
66
+ - **Guide** — start with the [Overview](guide/overview.md) (a map of every
67
+ capability) and [Getting Started](guide/getting-started.md).
68
+ - **[API reference](https://orionreed.github.io/bireactive/api/)** — every
69
+ export, grouped by domain; the guide lives in its sidebar too.
70
+ - **[Demos](https://orionreed.github.io/bireactive/)** — live, interactive examples.
71
+
64
72
  ## Develop
65
73
 
66
74
  ```sh
67
75
  npm run dev # serve the landing page at :5555
68
- npm run site # build the static site into dist-web/
76
+ npm run site # build the static site + API docs into dist-web/
77
+ npm run docs # build just the API reference + guide into dist-web/api/
69
78
  npm run build # compile the library into dist/
70
79
  npm test # run the test suite
71
80
  ```
72
81
 
73
82
  ## Status
74
83
 
75
- `0.x` — APIs are still moving. The package is a single bundle today;
76
- sub-packages (`@bireactive/core`, `@bireactive/animation`, `@bireactive/shapes`, …) are used
77
- internally as path aliases and will be split out once the surface settles.
84
+ `0.x` — APIs are still moving frequently. The package is a single bundle today; sub-packages will be split out once the surface settles.
78
85
 
79
86
  ## License
80
87
 
@@ -1,15 +1,8 @@
1
- // Counts-first instrumentation measurement scaffolding, not a public surface.
2
- //
3
- // The methodology (per the redesign brief): judge engine work by *counts*, not
4
- // timings. Every metric here is a discrete, predictable event a user callback
5
- // invoked, a codepath entered, a node visited, a reverse edge spliced — so a
6
- // correct minimal engine has a *calculable* target and any work above it is
7
- // provably wasted. This is the gate for the unification: a change must not raise
8
- // the forward counts and must hold the backward counts at their minimum.
9
- //
10
- // Off by default. `COUNTS` is one module-level gate; each instrumented site reads
11
- // `if (COUNTS) counts.x++`, so a downstream minifier sees `if (false)` and drops
12
- // it, and when on the cost is a single predictable branch. Flip via `withCounts`.
1
+ // Counts-first instrumentation: judge engine work by discrete event *counts*
2
+ // (callbacks invoked, codepaths entered, nodes visited, edges spliced), not
3
+ // timings, so a minimal engine has a calculable target. Off by default — each
4
+ // site reads `if (COUNTS) counts.x++`, so a minifier drops it when off and it
5
+ // costs one branch when on. Flip via `withCounts`.
13
6
  function fresh() {
14
7
  return {
15
8
  recompute: 0,
@@ -209,8 +209,8 @@ export declare class Cell<T = unknown> implements ReactiveNode {
209
209
  through<B>(this: Cell<T>, o: Optic<T, B>): Writable<Cell<B>>;
210
210
  through<B, C>(this: Cell<T>, o1: Optic<T, B>, o2: Optic<B, C>): Writable<Cell<C>>;
211
211
  through<B, C, D>(this: Cell<T>, o1: Optic<T, B>, o2: Optic<B, C>, o3: Optic<C, D>): Writable<Cell<D>>;
212
- /** Backward fan-in: forward the identity view of its parent, backward the point
213
- * where N contributors fold into one value. `fold` defaults to last-writer-wins. */
212
+ /** Backward fan-in: forwards its parent's value unchanged; on write, folds N
213
+ * contributors into one value. `fold` defaults to last-writer-wins. */
214
214
  merge(this: Cell<T>, fold?: MergeFold<T>): Cell<T>;
215
215
  /** Read-only typed view. `Cls.derive(parent, fn)` (1-input),
216
216
  * `Cls.derive(parents, fn)` (N-input), or `Cls.derive(fn)` (closure).
@@ -324,7 +324,7 @@ export declare function network(deps: readonly Cell<any>[], body: NetworkBody, o
324
324
  * get x() { return fieldLens(this, "x", Num); } */
325
325
  export declare function fieldLens<S extends Cell<any>, K extends keyof Inner<S>, C extends new (...args: never[]) => Cell<Inner<S>[K]>>(parent: S, key: K, Cls: C): S extends WritableBrand ? Writable<InstanceType<C>> : InstanceType<C>;
326
326
  /** Read-only derived view via `Cls.derive(parent, fn)`, memoized per
327
- * (instance, key). The cache is the point.
327
+ * (instance, key).
328
328
  *
329
329
  * get magnitude() {
330
330
  * return cachedDerive(this, "magnitude", Num, v => Math.hypot(v.x, v.y));
package/dist/core/cell.js CHANGED
@@ -754,8 +754,8 @@ export class Cell {
754
754
  : (target) => o.put(target, undefined);
755
755
  return lens(this, o.get, bwd);
756
756
  }
757
- /** Backward fan-in: forward the identity view of its parent, backward the point
758
- * where N contributors fold into one value. `fold` defaults to last-writer-wins. */
757
+ /** Backward fan-in: forwards its parent's value unchanged; on write, folds N
758
+ * contributors into one value. `fold` defaults to last-writer-wins. */
759
759
  merge(fold) {
760
760
  if (this.getter !== undefined && this._bwd === undefined) {
761
761
  throw new TypeError("merge: receiver is read-only");
@@ -1159,8 +1159,8 @@ function markDown(start) {
1159
1159
  * `writeBack`ing each. Source-centric — a source reflects all its writers, so a
1160
1160
  * call on it resolves every co-writer together and commits once.
1161
1161
  *
1162
- * Iterative post-order over the back-cone (was a recursion bounded by lens-nesting
1163
- * depth), via an explicit frame stack of {node, next-child cursor}. On entering a
1162
+ * Iterative post-order over the back-cone, via an explicit frame stack of
1163
+ * {node, next-child cursor}. On entering a
1164
1164
  * node (pre): clear a merge's contributions, then `writeBack` if it holds an armed
1165
1165
  * target. After its children drain (post): clear `BF.Pending`, then fold a merge.
1166
1166
  * Children are walked in forward `childEdges` order (so a co-writer's last write
@@ -1295,8 +1295,7 @@ function resolveBackDeps(node) {
1295
1295
  *
1296
1296
  * Iterative depth-first, left-to-right (children pushed in reverse onto the
1297
1297
  * pooled `wbNode`/`wbTarget` stack), so a sibling read sees a prior sibling's
1298
- * staged write exactly as the old recursion did — bounded by stack memory, not
1299
- * the call stack. */
1298
+ * staged write — bounded by pooled stack memory, not the call stack. */
1300
1299
  function writeBack(node, target) {
1301
1300
  wbNode[0] = node;
1302
1301
  wbTarget[0] = target;
@@ -1815,7 +1814,7 @@ export function fieldLens(parent, key, Cls) {
1815
1814
  return lazy(parent, key, () => fieldOf(parent, key, Cls));
1816
1815
  }
1817
1816
  /** Read-only derived view via `Cls.derive(parent, fn)`, memoized per
1818
- * (instance, key). The cache is the point.
1817
+ * (instance, key).
1819
1818
  *
1820
1819
  * get magnitude() {
1821
1820
  * return cachedDerive(this, "magnitude", Num, v => Math.hypot(v.x, v.y));
@@ -1,10 +1,7 @@
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`.
1
+ // Read-only geometric readouts over `Cls.derive`: one-way derives whose inverse
2
+ // is under-determined (a point at parameter `t` pins the curve at one point, but
3
+ // the control points keep many DOF). For the writable bezier decomposition see
4
+ // `bezierGestalt` in `lenses/geometry`.
8
5
  import { Vec } from "./values/vec.js";
9
6
  /** Quadratic Bézier point at parameter `t`. RO. */
10
7
  export function bezier2(p0, p1, p2, t) {
@@ -9,6 +9,7 @@ export { at, fields } from "./optics.js";
9
9
  export { type Store, store } from "./store.js";
10
10
  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";
11
11
  export { Anchor, Dir } from "./values/anchor.js";
12
+ export { Arr, allPass, arr, type CellPred, type Group, GroupArr, is, } from "./values/arr.js";
12
13
  export { Audio, type AudioClip, audio, stamp as audioStamp } from "./values/audio.js";
13
14
  export { Bool, bool } from "./values/bool.js";
14
15
  export { Box, box, edgeFrom as boxEdgeFrom, expand as boxExpand, union as boxUnion, } from "./values/box.js";
@@ -21,8 +22,9 @@ export { compose as matrixCompose, Matrix, matrix, toMatrixString, transformBox,
21
22
  export { Num, num } from "./values/num.js";
22
23
  export { Pose, pose } from "./values/pose.js";
23
24
  export { Range, range, span } from "./values/range.js";
25
+ export { type AltVal, type BindOpts, type Handle, type HandleKind, type HandleOf, Reg, type RegVal, type Silent, type StarVal, } from "./values/reg.js";
24
26
  export { Str, str } from "./values/str.js";
25
27
  export { type Codec, enumCodec, numCodec, route, type Slot, slot, strCodec, template, tpl, } from "./values/template.js";
26
28
  export { Transform, type TransformInit, transform } from "./values/transform.js";
27
29
  export { Tri, tri } from "./values/tri.js";
28
- export { type PolarPolicy, polar, tangentPoint, Vec, vec } from "./values/vec.js";
30
+ export { tangentPoint, Vec, vec } from "./values/vec.js";
@@ -9,6 +9,7 @@ export { at, fields } from "./optics.js";
9
9
  export { store } from "./store.js";
10
10
  export { requireEquals, requireLerp, requireLinear, requireMetric, requirePack, requirePivotal, } from "./traits.js";
11
11
  export { Anchor, Dir } from "./values/anchor.js";
12
+ export { Arr, allPass, arr, GroupArr, is, } from "./values/arr.js";
12
13
  export { Audio, audio, stamp as audioStamp } from "./values/audio.js";
13
14
  export { Bool, bool } from "./values/bool.js";
14
15
  export { Box, box, edgeFrom as boxEdgeFrom, expand as boxExpand, union as boxUnion, } from "./values/box.js";
@@ -21,8 +22,9 @@ export { compose as matrixCompose, Matrix, matrix, toMatrixString, transformBox,
21
22
  export { Num, num } from "./values/num.js";
22
23
  export { Pose, pose } from "./values/pose.js";
23
24
  export { Range, range, span } from "./values/range.js";
25
+ export { Reg, } from "./values/reg.js";
24
26
  export { Str, str } from "./values/str.js";
25
27
  export { enumCodec, numCodec, route, slot, strCodec, template, tpl, } from "./values/template.js";
26
28
  export { Transform, transform } from "./values/transform.js";
27
29
  export { Tri, tri } from "./values/tri.js";
28
- export { polar, tangentPoint, Vec, vec } from "./values/vec.js";
30
+ export { tangentPoint, Vec, vec } from "./values/vec.js";
@@ -1,53 +1,43 @@
1
- import { type Writable } from "../cell.js";
2
- import { Num } from "../values/num.js";
3
- import { Vec } from "../values/vec.js";
4
- export interface ArgminOpts {
5
- /** Finite-difference epsilon for the Jacobian. Default 1e-4. */
6
- eps?: number;
7
- /** Levenberg-Marquardt damping. Default `1e-6` for `argminNum`
8
- * (Jacobian is always well-conditioned for linear constraints) and
9
- * `1e-3` for `argminVec` (IK chains hit rank-deficient regimes at
10
- * full extension). Larger smaller, more stable updates; smaller
11
- * closer to pure pseudoinverse. */
12
- damping?: number;
13
- }
14
- /** Target-shaping for `argminVec`: project a write into the reachable
15
- * workspace before the Jacobian step, sidestepping the rank-deficient
16
- * swings at the boundary. For an N-link chain rooted at `R` with reach
17
- * `L`, pass `clampToDisc(R, L)`. */
18
- export interface ArgminVecOpts extends ArgminOpts {
19
- /** Pre-write hook: transform the requested target into one that's
20
- * guaranteed solvable. Most useful as a workspace clamp. */
21
- clampTarget?: (target: {
22
- x: number;
23
- y: number;
24
- }, currentInputs: readonly number[]) => {
25
- x: number;
26
- y: number;
27
- };
28
- }
29
- /** Project `p` into the closed disc of radius `r` centred on `c` (points
30
- * inside pass through). Use as `argminVec`'s `clampTarget` to fix IK
31
- * explosion at maximum reach. */
32
- export declare function clampToDisc(c: {
33
- x: number;
34
- y: number;
35
- }, r: number): (p: {
36
- x: number;
37
- y: number;
38
- }) => {
39
- x: number;
40
- y: number;
1
+ import { type Cell, Num, type Read, type Traits, type Val, type Writable } from "../index.js";
2
+ /** Equal-weight mean (writable of `inputs[0]`'s class); writes distribute
3
+ * the delta evenly. Class inferred from the first input; needs `linear`. */
4
+ export declare function mean<S extends Traits<any, "linear">>(inputs: readonly Writable<S>[]): Writable<S>;
5
+ /** Weighted blend of K branches over any `Linear` type: reads the normalized
6
+ * weighted sum `Σ wᵢ·aᵢ`, writes the minimum-norm delta back into the
7
+ * branches (zero-weight branches untouched). Weights are read-only reactive
8
+ * controls a one-hot is `select`, a `(1−t, t)` edge is `crossfade`. */
9
+ export declare function mix<S extends Traits<any, "linear">>(weights: readonly Val<number>[], branches: readonly Writable<S>[]): Writable<S>;
10
+ /** Two-branch router (mix simplex *vertex*): reads the live branch, writes
11
+ * flow entirely to it, the other is left put. Flipping `cond` snaps the
12
+ * output to the other branch's stored value. */
13
+ export declare function select<S extends Traits<any, "linear">>(cond: Read<boolean>, whenFalse: Writable<S>, whenTrue: Writable<S>): Writable<S>;
14
+ /** Two-branch crossfade (mix simplex *edge*): `lerp(a, b, t)`. Writing
15
+ * keeps `t` fixed and splits the delta by influence. */
16
+ export declare function crossfade<S extends Traits<any, "linear">>(t: Read<number>, a: Writable<S>, b: Writable<S>): Writable<S>;
17
+ /** Mean distance from the centroid (needs `Linear` + `Metric`); write scales
18
+ * the cluster's deviations so the new mean matches. The complement carries
19
+ * normalized deviations, so a collapse (spread 0) reinflates the shape. */
20
+ export declare function spread<T extends NonNullable<unknown>, S extends Cell<T> & Traits<T, "linear" | "metric">>(inputs: readonly Writable<S>[]): Writable<Num>;
21
+ /** Mean/spread decomposition: K values → {mean, spread}, i.e. centroid +
22
+ * uniform scale about it. `mean` ∘ `spread`; works for any
23
+ * Linear + Metric class (palettes, point clouds, poses, …). */
24
+ export declare function meanSpread<T extends NonNullable<unknown>, S extends Cell<T> & Traits<T, "linear" | "metric">>(colors: readonly Writable<S>[]): {
25
+ mean: Writable<S>;
26
+ spread: Writable<Num>;
27
+ };
28
+ /** (a, b) → {mean: (a+b)/2, diff: a−b}. Square linear iso; each write is the
29
+ * inverse change of basis, so mean and diff are cross-channel invariant. */
30
+ export declare function meanDiff(a: Num, b: Num): {
31
+ mean: Writable<Num>;
32
+ diff: Writable<Num>;
33
+ };
34
+ /** Mean of N nums, clamped to `[lo, hi]` on read and write (writes are
35
+ * clamped before the delta is distributed). */
36
+ export declare function clampedMean(parents: readonly Num[], lo: number, hi: number): Writable<Num>;
37
+ /** Num values as (i, valueᵢ) samples → {mean, slope}. Writing `mean` shifts
38
+ * all values; writing `slope` (least-squares) tilts them about the mean.
39
+ * Each preserves the other's reading. */
40
+ export declare function timeSeries(values: readonly Writable<Num>[]): {
41
+ mean: Writable<Num>;
42
+ slope: Writable<Num>;
41
43
  };
42
- /** Scalar-output argmin lens: write does one Newton step against the FD
43
- * Jacobian, distributing the residual by `weights`. For typed/multi-
44
- * output cases use `factor()`; this M=1 path is kept for its hand-rolled
45
- * inner loop. */
46
- export declare function argminNum(inputs: readonly Num[], forward: (xs: readonly number[]) => number, weights: readonly number[], opts?: ArgminOpts): Writable<Num>;
47
- /** 2D-output argmin lens (scalar Num inputs, `{x, y}` forward). For IK
48
- * arms, draggable points, handle projection. Kept for its hand-rolled
49
- * 2×2 inverse + `clampTarget` hook; see `factor()` for other M. */
50
- export declare function argminVec(inputs: readonly Num[], forward: (xs: readonly number[]) => {
51
- x: number;
52
- y: number;
53
- }, weights: readonly number[], opts?: ArgminVecOpts): Writable<Vec>;