bireactive 0.2.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.
Files changed (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -0
  3. package/dist/animation/anim.d.ts +57 -0
  4. package/dist/animation/anim.js +318 -0
  5. package/dist/animation/combinators.d.ts +39 -0
  6. package/dist/animation/combinators.js +113 -0
  7. package/dist/animation/easings.d.ts +5 -0
  8. package/dist/animation/easings.js +5 -0
  9. package/dist/animation/index.d.ts +3 -0
  10. package/dist/animation/index.js +3 -0
  11. package/dist/assert/algebra.d.ts +20 -0
  12. package/dist/assert/algebra.js +79 -0
  13. package/dist/assert/claim.d.ts +40 -0
  14. package/dist/assert/claim.js +129 -0
  15. package/dist/assert/index.d.ts +7 -0
  16. package/dist/assert/index.js +19 -0
  17. package/dist/assert/predicates.d.ts +18 -0
  18. package/dist/assert/predicates.js +43 -0
  19. package/dist/assert/record.d.ts +20 -0
  20. package/dist/assert/record.js +78 -0
  21. package/dist/assert/scope.d.ts +42 -0
  22. package/dist/assert/scope.js +233 -0
  23. package/dist/assert/span.d.ts +37 -0
  24. package/dist/assert/span.js +68 -0
  25. package/dist/assert/tree.d.ts +22 -0
  26. package/dist/assert/tree.js +65 -0
  27. package/dist/code/code.d.ts +70 -0
  28. package/dist/code/code.js +361 -0
  29. package/dist/code/index.d.ts +2 -0
  30. package/dist/code/index.js +9 -0
  31. package/dist/code/morph.d.ts +5 -0
  32. package/dist/code/morph.js +194 -0
  33. package/dist/code/tokenize.d.ts +8 -0
  34. package/dist/code/tokenize.js +51 -0
  35. package/dist/constraints/cluster.d.ts +83 -0
  36. package/dist/constraints/cluster.js +213 -0
  37. package/dist/constraints/drivers.d.ts +15 -0
  38. package/dist/constraints/drivers.js +40 -0
  39. package/dist/constraints/factories.d.ts +73 -0
  40. package/dist/constraints/factories.js +248 -0
  41. package/dist/constraints/index.d.ts +11 -0
  42. package/dist/constraints/index.js +39 -0
  43. package/dist/constraints/interaction.d.ts +21 -0
  44. package/dist/constraints/interaction.js +148 -0
  45. package/dist/constraints/linalg.d.ts +18 -0
  46. package/dist/constraints/linalg.js +141 -0
  47. package/dist/constraints/phases.d.ts +21 -0
  48. package/dist/constraints/phases.js +60 -0
  49. package/dist/constraints/physics.d.ts +34 -0
  50. package/dist/constraints/physics.js +128 -0
  51. package/dist/constraints/rigid.d.ts +210 -0
  52. package/dist/constraints/rigid.js +835 -0
  53. package/dist/constraints/solver.d.ts +107 -0
  54. package/dist/constraints/solver.js +510 -0
  55. package/dist/constraints/term.d.ts +50 -0
  56. package/dist/constraints/term.js +80 -0
  57. package/dist/constraints/terms.d.ts +80 -0
  58. package/dist/constraints/terms.js +302 -0
  59. package/dist/constraints/world.d.ts +31 -0
  60. package/dist/constraints/world.js +245 -0
  61. package/dist/core/aggregates.d.ts +64 -0
  62. package/dist/core/aggregates.js +198 -0
  63. package/dist/core/anim.d.ts +84 -0
  64. package/dist/core/anim.js +301 -0
  65. package/dist/core/index.d.ts +38 -0
  66. package/dist/core/index.js +38 -0
  67. package/dist/core/introspect.d.ts +5 -0
  68. package/dist/core/introspect.js +31 -0
  69. package/dist/core/lenses/closed-form-policies.d.ts +64 -0
  70. package/dist/core/lenses/closed-form-policies.js +452 -0
  71. package/dist/core/lenses/domain-aggregates.d.ts +54 -0
  72. package/dist/core/lenses/domain-aggregates.js +259 -0
  73. package/dist/core/lenses/factor-lens.d.ts +42 -0
  74. package/dist/core/lenses/factor-lens.js +419 -0
  75. package/dist/core/lenses/index.d.ts +5 -0
  76. package/dist/core/lenses/index.js +16 -0
  77. package/dist/core/lenses/memory.d.ts +47 -0
  78. package/dist/core/lenses/memory.js +102 -0
  79. package/dist/core/lenses/typed-factor.d.ts +45 -0
  80. package/dist/core/lenses/typed-factor.js +376 -0
  81. package/dist/core/network-utils.d.ts +14 -0
  82. package/dist/core/network-utils.js +62 -0
  83. package/dist/core/new-primitives.d.ts +33 -0
  84. package/dist/core/new-primitives.js +113 -0
  85. package/dist/core/signal.d.ts +254 -0
  86. package/dist/core/signal.js +1349 -0
  87. package/dist/core/traits.d.ts +61 -0
  88. package/dist/core/traits.js +56 -0
  89. package/dist/core/tree.d.ts +23 -0
  90. package/dist/core/tree.js +62 -0
  91. package/dist/core/values/anchor.d.ts +23 -0
  92. package/dist/core/values/anchor.js +23 -0
  93. package/dist/core/values/audio.d.ts +33 -0
  94. package/dist/core/values/audio.js +107 -0
  95. package/dist/core/values/bool.d.ts +37 -0
  96. package/dist/core/values/bool.js +75 -0
  97. package/dist/core/values/box.d.ts +77 -0
  98. package/dist/core/values/box.js +211 -0
  99. package/dist/core/values/canvas.d.ts +71 -0
  100. package/dist/core/values/canvas.js +495 -0
  101. package/dist/core/values/color.d.ts +49 -0
  102. package/dist/core/values/color.js +106 -0
  103. package/dist/core/values/flags.d.ts +18 -0
  104. package/dist/core/values/flags.js +50 -0
  105. package/dist/core/values/gpu.d.ts +74 -0
  106. package/dist/core/values/gpu.js +426 -0
  107. package/dist/core/values/matrix.d.ts +53 -0
  108. package/dist/core/values/matrix.js +140 -0
  109. package/dist/core/values/num.d.ts +62 -0
  110. package/dist/core/values/num.js +166 -0
  111. package/dist/core/values/pose.d.ts +31 -0
  112. package/dist/core/values/pose.js +83 -0
  113. package/dist/core/values/range.d.ts +83 -0
  114. package/dist/core/values/range.js +167 -0
  115. package/dist/core/values/str.d.ts +76 -0
  116. package/dist/core/values/str.js +346 -0
  117. package/dist/core/values/template.d.ts +49 -0
  118. package/dist/core/values/template.js +148 -0
  119. package/dist/core/values/transform.d.ts +49 -0
  120. package/dist/core/values/transform.js +115 -0
  121. package/dist/core/values/tri.d.ts +31 -0
  122. package/dist/core/values/tri.js +95 -0
  123. package/dist/core/values/vec.d.ts +72 -0
  124. package/dist/core/values/vec.js +219 -0
  125. package/dist/core/writable.d.ts +15 -0
  126. package/dist/core/writable.js +29 -0
  127. package/dist/ext/events.d.ts +10 -0
  128. package/dist/ext/events.js +31 -0
  129. package/dist/ext/index.d.ts +4 -0
  130. package/dist/ext/index.js +4 -0
  131. package/dist/ext/snapshot.d.ts +8 -0
  132. package/dist/ext/snapshot.js +29 -0
  133. package/dist/ext/timeline.d.ts +56 -0
  134. package/dist/ext/timeline.js +94 -0
  135. package/dist/ext/waapi.d.ts +25 -0
  136. package/dist/ext/waapi.js +198 -0
  137. package/dist/index.d.ts +8 -0
  138. package/dist/index.js +10 -0
  139. package/dist/propagators/index.d.ts +6 -0
  140. package/dist/propagators/index.js +6 -0
  141. package/dist/propagators/layout.d.ts +68 -0
  142. package/dist/propagators/layout.js +336 -0
  143. package/dist/propagators/network.d.ts +52 -0
  144. package/dist/propagators/network.js +185 -0
  145. package/dist/propagators/propagator.d.ts +12 -0
  146. package/dist/propagators/propagator.js +16 -0
  147. package/dist/propagators/range.d.ts +45 -0
  148. package/dist/propagators/range.js +147 -0
  149. package/dist/propagators/relations.d.ts +60 -0
  150. package/dist/propagators/relations.js +343 -0
  151. package/dist/shapes/annular-sector.d.ts +15 -0
  152. package/dist/shapes/annular-sector.js +64 -0
  153. package/dist/shapes/button.d.ts +14 -0
  154. package/dist/shapes/button.js +31 -0
  155. package/dist/shapes/choreographers.d.ts +22 -0
  156. package/dist/shapes/choreographers.js +69 -0
  157. package/dist/shapes/circle.d.ts +17 -0
  158. package/dist/shapes/circle.js +57 -0
  159. package/dist/shapes/clip.d.ts +5 -0
  160. package/dist/shapes/clip.js +31 -0
  161. package/dist/shapes/connect.d.ts +16 -0
  162. package/dist/shapes/connect.js +70 -0
  163. package/dist/shapes/curve.d.ts +60 -0
  164. package/dist/shapes/curve.js +285 -0
  165. package/dist/shapes/dashed.d.ts +16 -0
  166. package/dist/shapes/dashed.js +142 -0
  167. package/dist/shapes/debug.d.ts +43 -0
  168. package/dist/shapes/debug.js +97 -0
  169. package/dist/shapes/group.d.ts +5 -0
  170. package/dist/shapes/group.js +10 -0
  171. package/dist/shapes/handle.d.ts +32 -0
  172. package/dist/shapes/handle.js +88 -0
  173. package/dist/shapes/index.d.ts +23 -0
  174. package/dist/shapes/index.js +23 -0
  175. package/dist/shapes/interaction.d.ts +32 -0
  176. package/dist/shapes/interaction.js +187 -0
  177. package/dist/shapes/label.d.ts +20 -0
  178. package/dist/shapes/label.js +42 -0
  179. package/dist/shapes/layout.d.ts +29 -0
  180. package/dist/shapes/layout.js +74 -0
  181. package/dist/shapes/line.d.ts +21 -0
  182. package/dist/shapes/line.js +79 -0
  183. package/dist/shapes/list.d.ts +18 -0
  184. package/dist/shapes/list.js +51 -0
  185. package/dist/shapes/mount.d.ts +7 -0
  186. package/dist/shapes/mount.js +10 -0
  187. package/dist/shapes/path.d.ts +77 -0
  188. package/dist/shapes/path.js +227 -0
  189. package/dist/shapes/rect.d.ts +30 -0
  190. package/dist/shapes/rect.js +131 -0
  191. package/dist/shapes/shape.d.ts +132 -0
  192. package/dist/shapes/shape.js +306 -0
  193. package/dist/shapes/text.d.ts +24 -0
  194. package/dist/shapes/text.js +53 -0
  195. package/dist/shapes/tokens.d.ts +28 -0
  196. package/dist/shapes/tokens.js +27 -0
  197. package/dist/shapes/transitions.d.ts +23 -0
  198. package/dist/shapes/transitions.js +62 -0
  199. package/dist/tex/decorations.d.ts +26 -0
  200. package/dist/tex/decorations.js +116 -0
  201. package/dist/tex/index.d.ts +5 -0
  202. package/dist/tex/index.js +5 -0
  203. package/dist/tex/marker.d.ts +17 -0
  204. package/dist/tex/marker.js +63 -0
  205. package/dist/tex/motion.d.ts +43 -0
  206. package/dist/tex/motion.js +290 -0
  207. package/dist/tex/parts.d.ts +65 -0
  208. package/dist/tex/parts.js +149 -0
  209. package/dist/tex/tex.d.ts +45 -0
  210. package/dist/tex/tex.js +244 -0
  211. package/dist/web/attr.d.ts +16 -0
  212. package/dist/web/attr.js +98 -0
  213. package/dist/web/diagram.d.ts +49 -0
  214. package/dist/web/diagram.js +260 -0
  215. package/dist/web/index.d.ts +6 -0
  216. package/dist/web/index.js +6 -0
  217. package/dist/web/md-marker.d.ts +6 -0
  218. package/dist/web/md-marker.js +39 -0
  219. package/dist/web/md-tex.d.ts +6 -0
  220. package/dist/web/md-tex.js +61 -0
  221. package/dist/web/raf.d.ts +6 -0
  222. package/dist/web/raf.js +24 -0
  223. package/dist/web/viewport.d.ts +7 -0
  224. package/dist/web/viewport.js +13 -0
  225. package/package.json +87 -0
@@ -0,0 +1,61 @@
1
+ export interface Linear<T> {
2
+ add(a: T, b: T): T;
3
+ sub(a: T, b: T): T;
4
+ scale(a: T, k: number): T;
5
+ }
6
+ export type Lerp<T> = (a: T, b: T, t: number) => T;
7
+ export type Metric<T> = (a: T, b: T) => number;
8
+ export type Equals<T> = (a: T, b: T) => boolean;
9
+ /** Flat-buffer codec: view a typed value as a `dim`-sized slice of a
10
+ * shared `Float64Array`, read/written by offset to avoid allocations
11
+ * in hot numerical loops. */
12
+ export interface Pack<T> {
13
+ readonly dim: number;
14
+ read(value: T, into: Float64Array, offset: number): void;
15
+ write(from: Float64Array, offset: number): T;
16
+ }
17
+ /** 2-D group action: rotation + uniform scale about a pivot. Used by
18
+ * closed-form aggregate lenses ("rotate/scale the cluster about its
19
+ * centroid"). Per-value-class semantics — Pose rotates position AND
20
+ * orientation, Vec only position; pivot is always a 2-D `{x, y}`.
21
+ * Caller passes signed dθ (wraps) and k (k < 0 reflects). */
22
+ export interface Pivotal<T> {
23
+ rotateAbout(value: T, pivot: {
24
+ x: number;
25
+ y: number;
26
+ }, dθ: number): T;
27
+ scaleAbout(value: T, pivot: {
28
+ x: number;
29
+ y: number;
30
+ }, k: number): T;
31
+ }
32
+ /** Shape of a value class's `static traits` dict. Subclasses fill the
33
+ * subset they implement; consumers constrain on `Traits<T, …keys>`. */
34
+ export interface TraitDict<T> {
35
+ linear?: Linear<T>;
36
+ lerp?: Lerp<T>;
37
+ metric?: Metric<T>;
38
+ equals?: Equals<T>;
39
+ pack?: Pack<T>;
40
+ pivotal?: Pivotal<T>;
41
+ }
42
+ /** Valid keys of `TraitDict`. The set of declarable traits. */
43
+ export type TraitKey = keyof TraitDict<unknown>;
44
+ /** "A reactive whose class declares the listed traits." `_t` is a
45
+ * phantom slot typed against `typeof Cls.traits`; listed keys must
46
+ * resolve to non-null. Pure constraint — doesn't imply `Cell<T>`;
47
+ * intersect with `Writable<Cell<T>>` / `Read<T>` for capability.
48
+ *
49
+ * function spring<T>(sig: Traits<T, "linear" | "metric">, target: Val<T>)
50
+ * function tween<T>(sig: Traits<T, "lerp">, target: T, dur: Val<number>) */
51
+ export type Traits<T, K extends TraitKey = never> = {
52
+ readonly _t: {
53
+ [P in K]-?: NonNullable<TraitDict<T>[P]>;
54
+ } & TraitDict<T>;
55
+ };
56
+ export declare function requireLinear<T>(s: Traits<T, "linear">): Linear<T>;
57
+ export declare function requireLerp<T>(s: Traits<T, "lerp">): Lerp<T>;
58
+ export declare function requireMetric<T>(s: Traits<T, "metric">): Metric<T>;
59
+ export declare function requireEquals<T>(s: Traits<T, "equals">): Equals<T>;
60
+ export declare function requirePack<T>(s: Traits<T, "pack">): Pack<T>;
61
+ export declare function requirePivotal<T>(s: Traits<T, "pivotal">): Pivotal<T>;
@@ -0,0 +1,56 @@
1
+ // Traits — polymorphic interfaces declared on the class via a single
2
+ // `static traits = { … }` dictionary. One nominal constraint type
3
+ // `Traits<T, K>` covers any combination of required traits via a union
4
+ // of keys (no per-trait alias proliferation):
5
+ //
6
+ // function spring<T>(sig: Traits<T, "linear" | "metric">, target: Val<T>) …
7
+ // function tween<T>(sig: Traits<T, "lerp">, target: T, dur: Val<number>) …
8
+ //
9
+ // The dictionary shape is `TraitDict<T>`; `Traits<T, K>` is the
10
+ // constraint consumers see. Two separate axes:
11
+ // - Type level: `Traits<T, K>` requires a phantom `_t` slot typed
12
+ // against the class's static traits (`declare readonly _t: …`).
13
+ // - Runtime: `requireLinear` & siblings walk `s.constructor.traits.*`.
14
+ //
15
+ // The engine (signal.ts) is trait-ignorant; subclasses thread equality
16
+ // through `super(v, { equals })` themselves.
17
+ /** Class-level traits dictionary for any Cell subclass. */
18
+ const dictOf = (s) => s.constructor?.traits ?? {};
19
+ const className = (s) => s.constructor?.name ?? "?";
20
+ const missing = (s, slot) => new Error(`require${slot}: ${className(s)} has no traits.${slot.toLowerCase()}`);
21
+ export function requireLinear(s) {
22
+ const v = dictOf(s).linear;
23
+ if (!v)
24
+ throw missing(s, "Linear");
25
+ return v;
26
+ }
27
+ export function requireLerp(s) {
28
+ const v = dictOf(s).lerp;
29
+ if (!v)
30
+ throw missing(s, "Lerp");
31
+ return v;
32
+ }
33
+ export function requireMetric(s) {
34
+ const v = dictOf(s).metric;
35
+ if (!v)
36
+ throw missing(s, "Metric");
37
+ return v;
38
+ }
39
+ export function requireEquals(s) {
40
+ const v = dictOf(s).equals;
41
+ if (!v)
42
+ throw missing(s, "Equals");
43
+ return v;
44
+ }
45
+ export function requirePack(s) {
46
+ const v = dictOf(s).pack;
47
+ if (!v)
48
+ throw missing(s, "Pack");
49
+ return v;
50
+ }
51
+ export function requirePivotal(s) {
52
+ const v = dictOf(s).pivotal;
53
+ if (!v)
54
+ throw missing(s, "Pivotal");
55
+ return v;
56
+ }
@@ -0,0 +1,23 @@
1
+ /** Recursive container: a value plus zero-or-more children of the same
2
+ * shape. Value is unconstrained — a single cell or a compound record
3
+ * (e.g. a bone with local + world poses). Structural edits go through
4
+ * `network()`. */
5
+ export interface TreeNode<T> {
6
+ readonly value: T;
7
+ readonly children: readonly TreeNode<T>[];
8
+ }
9
+ /** Construct a tree node. */
10
+ export declare function node<T>(value: T, children?: readonly TreeNode<T>[]): TreeNode<T>;
11
+ /** Depth-first traversal. `visit` receives the node, its depth from
12
+ * the root, and the path of child-indices from the root. */
13
+ export declare function walkTree<T>(root: TreeNode<T>, visit: (n: TreeNode<T>, depth: number, path: readonly number[]) => void): void;
14
+ /** Collect every leaf (a node with no children) in depth-first order. */
15
+ export declare function leavesOf<T>(root: TreeNode<T>): TreeNode<T>[];
16
+ /** Collect every node (leaf and internal) in depth-first order. */
17
+ export declare function allNodes<T>(root: TreeNode<T>): TreeNode<T>[];
18
+ /** Index a node by path from root. Empty path returns root. */
19
+ export declare function atPath<T>(root: TreeNode<T>, path: readonly number[]): TreeNode<T>;
20
+ /** True iff `n` is a leaf (no children). */
21
+ export declare function isLeaf<T>(n: TreeNode<T>): boolean;
22
+ /** Count nodes in the tree. */
23
+ export declare function nodeCount<T>(root: TreeNode<T>): number;
@@ -0,0 +1,62 @@
1
+ // tree.ts — hierarchical structure of (typically reactive) values.
2
+ //
3
+ // A `TreeNode<T>` is the structural relationship between values, not a
4
+ // single big `Cell<TreeShape>`. Each node's value is typically a
5
+ // Cell subclass or a compound of cells; writes flow through the
6
+ // individual cells with the engine's usual O(1) incrementality.
7
+ //
8
+ // Two bidirectional patterns layer on top (as free factory functions):
9
+ // 1. AGGREGATE (bottom-up): an internal node lenses over its leaves —
10
+ // merge on read, redistribute on write (sum-trees, mean-trees, …).
11
+ // 2. PROPAGATE (top-down): each node carries a local value; its
12
+ // "world" view composes the parent's with its own. The classical
13
+ // scene-graph / armature shape, parametrised by compose/decompose.
14
+ /** Construct a tree node. */
15
+ export function node(value, children = []) {
16
+ return { value, children };
17
+ }
18
+ /** Depth-first traversal. `visit` receives the node, its depth from
19
+ * the root, and the path of child-indices from the root. */
20
+ export function walkTree(root, visit) {
21
+ const inner = (n, depth, path) => {
22
+ visit(n, depth, path);
23
+ for (let i = 0; i < n.children.length; i++) {
24
+ inner(n.children[i], depth + 1, [...path, i]);
25
+ }
26
+ };
27
+ inner(root, 0, []);
28
+ }
29
+ /** Collect every leaf (a node with no children) in depth-first order. */
30
+ export function leavesOf(root) {
31
+ const out = [];
32
+ walkTree(root, n => {
33
+ if (n.children.length === 0)
34
+ out.push(n);
35
+ });
36
+ return out;
37
+ }
38
+ /** Collect every node (leaf and internal) in depth-first order. */
39
+ export function allNodes(root) {
40
+ const out = [];
41
+ walkTree(root, n => out.push(n));
42
+ return out;
43
+ }
44
+ /** Index a node by path from root. Empty path returns root. */
45
+ export function atPath(root, path) {
46
+ let n = root;
47
+ for (const i of path)
48
+ n = n.children[i];
49
+ return n;
50
+ }
51
+ /** True iff `n` is a leaf (no children). */
52
+ export function isLeaf(n) {
53
+ return n.children.length === 0;
54
+ }
55
+ /** Count nodes in the tree. */
56
+ export function nodeCount(root) {
57
+ let c = 0;
58
+ walkTree(root, () => {
59
+ c++;
60
+ });
61
+ return c;
62
+ }
@@ -0,0 +1,23 @@
1
+ import type { Inner } from "../signal.js";
2
+ import type { Vec } from "./vec.js";
3
+ type V = Inner<Vec>;
4
+ /** Anchor points on the unit box (`Center = {0.5, 0.5}`). */
5
+ export declare const Anchor: {
6
+ TopLeft: V;
7
+ Top: V;
8
+ TopRight: V;
9
+ Left: V;
10
+ Center: V;
11
+ Right: V;
12
+ BottomLeft: V;
13
+ Bottom: V;
14
+ BottomRight: V;
15
+ };
16
+ /** Unit direction vectors (y-down: `Up = {0,-1}`). */
17
+ export declare const Dir: {
18
+ Left: V;
19
+ Right: V;
20
+ Up: V;
21
+ Down: V;
22
+ };
23
+ export {};
@@ -0,0 +1,23 @@
1
+ // anchor.ts — points on the unit box `[0,1]²` (registration on a shape).
2
+ // dir.ts — unit direction vectors in `[-1,1]²` (displacement from rest).
3
+ //
4
+ // Plain constants — no reactive wrapping. Use as defaults / arguments.
5
+ /** Anchor points on the unit box (`Center = {0.5, 0.5}`). */
6
+ export const Anchor = {
7
+ TopLeft: { x: 0, y: 0 },
8
+ Top: { x: 0.5, y: 0 },
9
+ TopRight: { x: 1, y: 0 },
10
+ Left: { x: 0, y: 0.5 },
11
+ Center: { x: 0.5, y: 0.5 },
12
+ Right: { x: 1, y: 0.5 },
13
+ BottomLeft: { x: 0, y: 1 },
14
+ Bottom: { x: 0.5, y: 1 },
15
+ BottomRight: { x: 1, y: 1 },
16
+ };
17
+ /** Unit direction vectors (y-down: `Up = {0,-1}`). */
18
+ export const Dir = {
19
+ Left: { x: -1, y: 0 },
20
+ Right: { x: 1, y: 0 },
21
+ Up: { x: 0, y: -1 },
22
+ Down: { x: 0, y: 1 },
23
+ };
@@ -0,0 +1,33 @@
1
+ import { Cell, type Init, type Val, type Writable } from "../signal.js";
2
+ import { Num } from "./num.js";
3
+ /** Clip header. The graph compares `epoch`; `pcm` is one channel buffer each. */
4
+ export interface AudioClip {
5
+ readonly pcm: readonly Float32Array[];
6
+ readonly sampleRate: number;
7
+ readonly epoch: number;
8
+ }
9
+ type V = AudioClip;
10
+ /** Stamp channel buffers with a fresh epoch — the only way to mint a value. */
11
+ export declare const stamp: (pcm: readonly Float32Array[], sampleRate: number) => V;
12
+ export declare const equals: (a: V, b: V) => boolean;
13
+ export declare class Audio extends Cell<V> {
14
+ static traits: {
15
+ equals: (a: V, b: V) => boolean;
16
+ };
17
+ readonly _t: typeof Audio.traits;
18
+ constructor(v?: V);
19
+ /** Time-reverse every channel. Involution. */
20
+ reverse(): this;
21
+ /** Scalar gain. Invertible while k ≠ 0 — the audio twin of Canvas.brightness. */
22
+ gain(k: Val<number>): this;
23
+ /** Peak-normalize to reactive `target` (default 1). The view alone can't
24
+ * know the source's loudness, so the complement carries the original peak and
25
+ * the backward pass restores it. The audio analog of str.lowercase(). */
26
+ normalize(target?: Val<number>): Writable<Audio>;
27
+ /** RMS loudness as a writable `Num`; writing rescales the clip to hit it. */
28
+ rms(): Writable<Num>;
29
+ }
30
+ /** Writable `Audio`. A `Clip` seeds a fresh cell; an existing `Writable<Audio>`
31
+ * passes through by identity. */
32
+ export declare function audio(v: Init<Audio>): Writable<Audio>;
33
+ export {};
@@ -0,0 +1,107 @@
1
+ // audio.ts — reactive audio clip (handle-as-value), the sound twin of canvas.ts.
2
+ //
3
+ // A Clip is context-free PCM: one Float32Array per channel plus a sample rate.
4
+ // The graph transports only the tiny header {pcm, sampleRate, epoch} and compares
5
+ // the monotonic epoch, so propagation never scans a sample and nothing is copied
6
+ // across the bus (same handle-as-value rule as Canvas, minus the GL context — PCM
7
+ // needs no ambient AudioContext, that only appears at the playback sink).
8
+ //
9
+ // Tiers mirror the rest of values/:
10
+ // - pure isomorphisms (`reverse`) — one pass each way.
11
+ // - reactive-param invertible (`gain(k)`) — reads `Val<number>`.
12
+ // - complement projection (`normalize`) — the lossy view (peak-scaled) plus a
13
+ // complement (the original peak) recovered on write-back, the audio analog of
14
+ // str.lowercase()/canvas.grayscale().
15
+ // - cross-type lens (`rms` → Num).
16
+ import { Cell, reader } from "../signal.js";
17
+ import { Num } from "./num.js";
18
+ let EPOCH = 0;
19
+ /** Stamp channel buffers with a fresh epoch — the only way to mint a value. */
20
+ export const stamp = (pcm, sampleRate) => ({
21
+ pcm,
22
+ sampleRate,
23
+ epoch: ++EPOCH,
24
+ });
25
+ export const equals = (a, b) => a.epoch === b.epoch;
26
+ const peak = (v) => {
27
+ let m = 0;
28
+ for (const ch of v.pcm) {
29
+ for (let i = 0; i < ch.length; i++) {
30
+ const a = ch[i] < 0 ? -ch[i] : ch[i];
31
+ if (a > m)
32
+ m = a;
33
+ }
34
+ }
35
+ return m;
36
+ };
37
+ const rmsOf = (v) => {
38
+ let sum = 0;
39
+ let n = 0;
40
+ for (const ch of v.pcm) {
41
+ for (let i = 0; i < ch.length; i++)
42
+ sum += ch[i] * ch[i];
43
+ n += ch.length;
44
+ }
45
+ return n === 0 ? 0 : Math.sqrt(sum / n);
46
+ };
47
+ const scaled = (v, k) => stamp(v.pcm.map(ch => {
48
+ const o = new Float32Array(ch.length);
49
+ for (let i = 0; i < ch.length; i++)
50
+ o[i] = ch[i] * k;
51
+ return o;
52
+ }), v.sampleRate);
53
+ export class Audio extends Cell {
54
+ static traits = { equals };
55
+ constructor(v = { pcm: [], sampleRate: 44100, epoch: 0 }) {
56
+ super(v, { equals });
57
+ }
58
+ /** Time-reverse every channel. Involution. */
59
+ reverse() {
60
+ const run = (v) => stamp(v.pcm.map(ch => {
61
+ const o = new Float32Array(ch.length);
62
+ for (let i = 0; i < ch.length; i++)
63
+ o[i] = ch[ch.length - 1 - i];
64
+ return o;
65
+ }), v.sampleRate);
66
+ return this.lens(run, run);
67
+ }
68
+ /** Scalar gain. Invertible while k ≠ 0 — the audio twin of Canvas.brightness. */
69
+ gain(k) {
70
+ const kf = reader(k);
71
+ return this.lens(v => scaled(v, kf()), n => scaled(n, 1 / kf()));
72
+ }
73
+ /** Peak-normalize to reactive `target` (default 1). The view alone can't
74
+ * know the source's loudness, so the complement carries the original peak and
75
+ * the backward pass restores it. The audio analog of str.lowercase(). */
76
+ normalize(target = 1) {
77
+ const tf = reader(target);
78
+ const self = this;
79
+ return Audio.lens([self], {
80
+ init: ([s]) => peak(s),
81
+ step: ([s], c, external) => (external ? peak(s) : c),
82
+ fwd: ([s]) => {
83
+ const p = peak(s);
84
+ return p === 0 ? s : scaled(s, tf() / p);
85
+ },
86
+ bwd: (view, _src, c) => {
87
+ const t = tf();
88
+ return { updates: [t === 0 ? view : scaled(view, c / t)], complement: c };
89
+ },
90
+ });
91
+ }
92
+ /** RMS loudness as a writable `Num`; writing rescales the clip to hit it. */
93
+ rms() {
94
+ const self = this;
95
+ return Num.lens(self, v => rmsOf(v), (target, v) => {
96
+ const cur = rmsOf(v);
97
+ return cur === 0 ? v : scaled(v, target / cur);
98
+ });
99
+ }
100
+ }
101
+ /** Writable `Audio`. A `Clip` seeds a fresh cell; an existing `Writable<Audio>`
102
+ * passes through by identity. */
103
+ export function audio(v) {
104
+ if (v instanceof Audio)
105
+ return v;
106
+ return new Audio(v);
107
+ }
@@ -0,0 +1,37 @@
1
+ import { Cell, type Init, type Val, type Writable } from "../signal.js";
2
+ import type { Linear } from "../traits.js";
3
+ type V = boolean;
4
+ export declare const not: (a: V) => V;
5
+ export declare const and: (a: V, b: V) => V;
6
+ export declare const or: (a: V, b: V) => V;
7
+ export declare const xor: (a: V, b: V) => V;
8
+ export declare const equals: (a: V, b: V) => boolean;
9
+ export declare class Bool extends Cell<V> {
10
+ static traits: {
11
+ linear: Linear<boolean>;
12
+ equals: (a: V, b: V) => boolean;
13
+ };
14
+ readonly _t: typeof Bool.traits;
15
+ constructor(v?: V);
16
+ /** Logical negation. Involution; chains compose. */
17
+ not(): this;
18
+ /** Symmetric difference / parity. Invertible:
19
+ * `a ^ b = c ↔ a = c ^ b`. The F₂ analog of `Num#add`. */
20
+ xor(b: Val<V>): this;
21
+ /** `this && b`. RO: fan-in write-back isn't unique — use
22
+ * `Bool.lens([a, b], ...)` with an explicit policy for a writable AND. */
23
+ and(b: Val<V>): Bool;
24
+ or(b: Val<V>): Bool;
25
+ /** `this → b ≡ ¬this ∨ b`. */
26
+ implies(b: Val<V>): Bool;
27
+ /** Boolean equality — XNOR. */
28
+ eq(b: Val<V>): Bool;
29
+ nand(b: Val<V>): Bool;
30
+ nor(b: Val<V>): Bool;
31
+ }
32
+ /** Writable `Bool`. Literal seeds a fresh cell; existing `Writable<Bool>`
33
+ * passes through by identity. RO sources are rejected at the type level —
34
+ * use `Bool.derive(...)` for reactive RO tracking, or `cell.value` to
35
+ * snapshot. */
36
+ export declare function bool(v?: Init<Bool>): Writable<Bool>;
37
+ export {};
@@ -0,0 +1,75 @@
1
+ // bool.ts — reactive boolean.
2
+ //
3
+ // Invertibles ride the plain endo `.lens(fwd, bwd)`: `not()` (involution,
4
+ // `.not().not()` round-trips to identity) and `xor(b)` (its own inverse;
5
+ // `a ^ b = c ↔ a = c ^ b`). xor carries Bool's `linear` trait.
6
+ //
7
+ // `and` / `or` / `implies` / `eq` / `nand` / `nor` return bare RO `Bool`
8
+ // — lossy fan-ins whose write-back is ambiguous. Lift to writable via
9
+ // `Bool.lens([a, b], fwd, bwd)` with an explicit policy.
10
+ import { Cell, reader } from "../signal.js";
11
+ export const not = (a) => !a;
12
+ export const and = (a, b) => a && b;
13
+ export const or = (a, b) => a || b;
14
+ export const xor = (a, b) => a !== b;
15
+ export const equals = (a, b) => a === b;
16
+ // F₂-linear structure: xor is both add and sub (a ^ a = false);
17
+ // scale-by-integer collapses by parity (even k → false, odd k → a).
18
+ const linearImpl = {
19
+ add: xor,
20
+ sub: xor,
21
+ scale: (a, k) => (Math.round(k) % 2 !== 0 ? a : false),
22
+ };
23
+ export class Bool extends Cell {
24
+ static traits = { linear: linearImpl, equals };
25
+ constructor(v = false) {
26
+ super(v, { equals });
27
+ }
28
+ /** Logical negation. Involution; chains compose. */
29
+ not() {
30
+ return this.lens(not, not);
31
+ }
32
+ /** Symmetric difference / parity. Invertible:
33
+ * `a ^ b = c ↔ a = c ^ b`. The F₂ analog of `Num#add`. */
34
+ xor(b) {
35
+ const bf = reader(b);
36
+ return this.lens(v => v !== bf(), n => n !== bf());
37
+ }
38
+ /** `this && b`. RO: fan-in write-back isn't unique — use
39
+ * `Bool.lens([a, b], ...)` with an explicit policy for a writable AND. */
40
+ and(b) {
41
+ const bf = reader(b);
42
+ return Bool.derive(() => this.value && bf());
43
+ }
44
+ or(b) {
45
+ const bf = reader(b);
46
+ return Bool.derive(() => this.value || bf());
47
+ }
48
+ /** `this → b ≡ ¬this ∨ b`. */
49
+ implies(b) {
50
+ const bf = reader(b);
51
+ return Bool.derive(() => !this.value || bf());
52
+ }
53
+ /** Boolean equality — XNOR. */
54
+ eq(b) {
55
+ const bf = reader(b);
56
+ return Bool.derive(() => this.value === bf());
57
+ }
58
+ nand(b) {
59
+ const bf = reader(b);
60
+ return Bool.derive(() => !(this.value && bf()));
61
+ }
62
+ nor(b) {
63
+ const bf = reader(b);
64
+ return Bool.derive(() => !(this.value || bf()));
65
+ }
66
+ }
67
+ /** Writable `Bool`. Literal seeds a fresh cell; existing `Writable<Bool>`
68
+ * passes through by identity. RO sources are rejected at the type level —
69
+ * use `Bool.derive(...)` for reactive RO tracking, or `cell.value` to
70
+ * snapshot. */
71
+ export function bool(v = false) {
72
+ if (v instanceof Bool)
73
+ return v;
74
+ return new Bool(v);
75
+ }
@@ -0,0 +1,77 @@
1
+ import type { Easing } from "../../animation/index.js";
2
+ import { type Tween } from "../anim.js";
3
+ import { Cell, type Init, type Inner, type Val, type Writable, type WritableBrand } from "../signal.js";
4
+ import type { Linear, Pack } from "../traits.js";
5
+ import { Bool } from "./bool.js";
6
+ import { Num } from "./num.js";
7
+ import { Vec } from "./vec.js";
8
+ type V = {
9
+ x: number;
10
+ y: number;
11
+ w: number;
12
+ h: number;
13
+ };
14
+ export declare const add: (a: V, b: V) => V;
15
+ export declare const sub: (a: V, b: V) => V;
16
+ export declare const scale: (a: V, k: number) => V;
17
+ export declare const lerp: (a: V, b: V, t: number) => V;
18
+ export declare const equals: (a: V, b: V) => boolean;
19
+ /** L2 distance over the flat (x, y, w, h) representation. */
20
+ export declare const metric: (a: V, b: V) => number;
21
+ export declare const expand: (b: V, n: number) => V;
22
+ export declare const contains: (b: V, p: Inner<Vec>) => boolean;
23
+ /** Closest point inside `b` to `p`. Already-inside is identity; outside
24
+ * snaps to the nearest boundary point. `Box#contains`'s true-side bwd. */
25
+ export declare const clampToBox: (p: Inner<Vec>, b: V) => Inner<Vec>;
26
+ /** Closest point strictly outside `b` to `p`, displaced past the nearest
27
+ * edge by `eps`. Already-outside is identity. `Box#contains`'s
28
+ * false-side bwd. */
29
+ export declare const ejectFromBox: (p: Inner<Vec>, b: V, eps?: number) => Inner<Vec>;
30
+ /** Bounding box around a set of boxes. */
31
+ export declare function union(...bs: V[]): V;
32
+ /** Perimeter point on a Box facing `toward`. Default `Shape.boundary`. */
33
+ export declare function edgeFrom(b: V, toward: Inner<Vec>): Inner<Vec>;
34
+ export declare class Box extends Cell<V> {
35
+ static traits: {
36
+ linear: Linear<V>;
37
+ lerp: (a: V, b: V, t: number) => V;
38
+ metric: (a: V, b: V) => number;
39
+ equals: (a: V, b: V) => boolean;
40
+ pack: Pack<V>;
41
+ };
42
+ readonly _t: typeof Box.traits;
43
+ constructor(v?: V);
44
+ add(b: Val<V>): this;
45
+ sub(b: Val<V>): this;
46
+ scale(k: Val<number>): this;
47
+ expand(n: Val<number>): this;
48
+ lerp(b: Val<V>, t: Val<number>): Box;
49
+ /** Membership predicate. Conditional return type: a writable `Vec`
50
+ * yields `Writable<Bool>` and flipping the view moves the source —
51
+ * `true` clamps to the nearest in-box point, `false` ejects past the
52
+ * nearest edge by `eps`. Literal / RO inputs yield a bare RO `Bool`. */
53
+ contains<P extends Val<Inner<Vec>>>(p: P): P extends WritableBrand ? Writable<Bool> : Bool;
54
+ get x(): this extends WritableBrand ? Writable<Num> : Num;
55
+ get y(): this extends WritableBrand ? Writable<Num> : Num;
56
+ get w(): this extends WritableBrand ? Writable<Num> : Num;
57
+ get h(): this extends WritableBrand ? Writable<Num> : Num;
58
+ get area(): Num;
59
+ /** Vec at parametric (u, v) within `[0,1]²`. Not memoised (arbitrary
60
+ * pairs would leak a cache entry each) — use the named edge getters
61
+ * (`.center`, `.top`, …) for stable identity. */
62
+ at(u: number, v: number): Vec;
63
+ get center(): Vec;
64
+ get top(): Vec;
65
+ get bottom(): Vec;
66
+ get left(): Vec;
67
+ get right(): Vec;
68
+ /** Tween-builder, implied by the lerp trait. */
69
+ to(this: Writable<Box>, target: V, dur: Val<number>, ease?: Easing): Tween<V>;
70
+ }
71
+ /** Writable `Box` at `(x, y, w, h)`. Each component is a literal `number`
72
+ * (lifted to a fresh seed) or an existing `Writable<Num>` (identity
73
+ * passthrough). RO sources are rejected at the type level — use
74
+ * `Box.derive(...)` for reactive RO tracking, or `cell.value` to
75
+ * snapshot. Lock a component with `Num.pin(c)`. */
76
+ export declare function box(x?: Init<Num>, y?: Init<Num>, w?: Init<Num>, h?: Init<Num>): Writable<Box>;
77
+ export {};