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.
- package/LICENSE +21 -0
- package/README.md +81 -0
- package/dist/animation/anim.d.ts +57 -0
- package/dist/animation/anim.js +318 -0
- package/dist/animation/combinators.d.ts +39 -0
- package/dist/animation/combinators.js +113 -0
- package/dist/animation/easings.d.ts +5 -0
- package/dist/animation/easings.js +5 -0
- package/dist/animation/index.d.ts +3 -0
- package/dist/animation/index.js +3 -0
- package/dist/assert/algebra.d.ts +20 -0
- package/dist/assert/algebra.js +79 -0
- package/dist/assert/claim.d.ts +40 -0
- package/dist/assert/claim.js +129 -0
- package/dist/assert/index.d.ts +7 -0
- package/dist/assert/index.js +19 -0
- package/dist/assert/predicates.d.ts +18 -0
- package/dist/assert/predicates.js +43 -0
- package/dist/assert/record.d.ts +20 -0
- package/dist/assert/record.js +78 -0
- package/dist/assert/scope.d.ts +42 -0
- package/dist/assert/scope.js +233 -0
- package/dist/assert/span.d.ts +37 -0
- package/dist/assert/span.js +68 -0
- package/dist/assert/tree.d.ts +22 -0
- package/dist/assert/tree.js +65 -0
- package/dist/code/code.d.ts +70 -0
- package/dist/code/code.js +361 -0
- package/dist/code/index.d.ts +2 -0
- package/dist/code/index.js +9 -0
- package/dist/code/morph.d.ts +5 -0
- package/dist/code/morph.js +194 -0
- package/dist/code/tokenize.d.ts +8 -0
- package/dist/code/tokenize.js +51 -0
- package/dist/constraints/cluster.d.ts +83 -0
- package/dist/constraints/cluster.js +213 -0
- package/dist/constraints/drivers.d.ts +15 -0
- package/dist/constraints/drivers.js +40 -0
- package/dist/constraints/factories.d.ts +73 -0
- package/dist/constraints/factories.js +248 -0
- package/dist/constraints/index.d.ts +11 -0
- package/dist/constraints/index.js +39 -0
- package/dist/constraints/interaction.d.ts +21 -0
- package/dist/constraints/interaction.js +148 -0
- package/dist/constraints/linalg.d.ts +18 -0
- package/dist/constraints/linalg.js +141 -0
- package/dist/constraints/phases.d.ts +21 -0
- package/dist/constraints/phases.js +60 -0
- package/dist/constraints/physics.d.ts +34 -0
- package/dist/constraints/physics.js +128 -0
- package/dist/constraints/rigid.d.ts +210 -0
- package/dist/constraints/rigid.js +835 -0
- package/dist/constraints/solver.d.ts +107 -0
- package/dist/constraints/solver.js +510 -0
- package/dist/constraints/term.d.ts +50 -0
- package/dist/constraints/term.js +80 -0
- package/dist/constraints/terms.d.ts +80 -0
- package/dist/constraints/terms.js +302 -0
- package/dist/constraints/world.d.ts +31 -0
- package/dist/constraints/world.js +245 -0
- package/dist/core/aggregates.d.ts +64 -0
- package/dist/core/aggregates.js +198 -0
- package/dist/core/anim.d.ts +84 -0
- package/dist/core/anim.js +301 -0
- package/dist/core/index.d.ts +38 -0
- package/dist/core/index.js +38 -0
- package/dist/core/introspect.d.ts +5 -0
- package/dist/core/introspect.js +31 -0
- package/dist/core/lenses/closed-form-policies.d.ts +64 -0
- package/dist/core/lenses/closed-form-policies.js +452 -0
- package/dist/core/lenses/domain-aggregates.d.ts +54 -0
- package/dist/core/lenses/domain-aggregates.js +259 -0
- package/dist/core/lenses/factor-lens.d.ts +42 -0
- package/dist/core/lenses/factor-lens.js +419 -0
- package/dist/core/lenses/index.d.ts +5 -0
- package/dist/core/lenses/index.js +16 -0
- package/dist/core/lenses/memory.d.ts +47 -0
- package/dist/core/lenses/memory.js +102 -0
- package/dist/core/lenses/typed-factor.d.ts +45 -0
- package/dist/core/lenses/typed-factor.js +376 -0
- package/dist/core/network-utils.d.ts +14 -0
- package/dist/core/network-utils.js +62 -0
- package/dist/core/new-primitives.d.ts +33 -0
- package/dist/core/new-primitives.js +113 -0
- package/dist/core/signal.d.ts +254 -0
- package/dist/core/signal.js +1349 -0
- package/dist/core/traits.d.ts +61 -0
- package/dist/core/traits.js +56 -0
- package/dist/core/tree.d.ts +23 -0
- package/dist/core/tree.js +62 -0
- package/dist/core/values/anchor.d.ts +23 -0
- package/dist/core/values/anchor.js +23 -0
- package/dist/core/values/audio.d.ts +33 -0
- package/dist/core/values/audio.js +107 -0
- package/dist/core/values/bool.d.ts +37 -0
- package/dist/core/values/bool.js +75 -0
- package/dist/core/values/box.d.ts +77 -0
- package/dist/core/values/box.js +211 -0
- package/dist/core/values/canvas.d.ts +71 -0
- package/dist/core/values/canvas.js +495 -0
- package/dist/core/values/color.d.ts +49 -0
- package/dist/core/values/color.js +106 -0
- package/dist/core/values/flags.d.ts +18 -0
- package/dist/core/values/flags.js +50 -0
- package/dist/core/values/gpu.d.ts +74 -0
- package/dist/core/values/gpu.js +426 -0
- package/dist/core/values/matrix.d.ts +53 -0
- package/dist/core/values/matrix.js +140 -0
- package/dist/core/values/num.d.ts +62 -0
- package/dist/core/values/num.js +166 -0
- package/dist/core/values/pose.d.ts +31 -0
- package/dist/core/values/pose.js +83 -0
- package/dist/core/values/range.d.ts +83 -0
- package/dist/core/values/range.js +167 -0
- package/dist/core/values/str.d.ts +76 -0
- package/dist/core/values/str.js +346 -0
- package/dist/core/values/template.d.ts +49 -0
- package/dist/core/values/template.js +148 -0
- package/dist/core/values/transform.d.ts +49 -0
- package/dist/core/values/transform.js +115 -0
- package/dist/core/values/tri.d.ts +31 -0
- package/dist/core/values/tri.js +95 -0
- package/dist/core/values/vec.d.ts +72 -0
- package/dist/core/values/vec.js +219 -0
- package/dist/core/writable.d.ts +15 -0
- package/dist/core/writable.js +29 -0
- package/dist/ext/events.d.ts +10 -0
- package/dist/ext/events.js +31 -0
- package/dist/ext/index.d.ts +4 -0
- package/dist/ext/index.js +4 -0
- package/dist/ext/snapshot.d.ts +8 -0
- package/dist/ext/snapshot.js +29 -0
- package/dist/ext/timeline.d.ts +56 -0
- package/dist/ext/timeline.js +94 -0
- package/dist/ext/waapi.d.ts +25 -0
- package/dist/ext/waapi.js +198 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +10 -0
- package/dist/propagators/index.d.ts +6 -0
- package/dist/propagators/index.js +6 -0
- package/dist/propagators/layout.d.ts +68 -0
- package/dist/propagators/layout.js +336 -0
- package/dist/propagators/network.d.ts +52 -0
- package/dist/propagators/network.js +185 -0
- package/dist/propagators/propagator.d.ts +12 -0
- package/dist/propagators/propagator.js +16 -0
- package/dist/propagators/range.d.ts +45 -0
- package/dist/propagators/range.js +147 -0
- package/dist/propagators/relations.d.ts +60 -0
- package/dist/propagators/relations.js +343 -0
- package/dist/shapes/annular-sector.d.ts +15 -0
- package/dist/shapes/annular-sector.js +64 -0
- package/dist/shapes/button.d.ts +14 -0
- package/dist/shapes/button.js +31 -0
- package/dist/shapes/choreographers.d.ts +22 -0
- package/dist/shapes/choreographers.js +69 -0
- package/dist/shapes/circle.d.ts +17 -0
- package/dist/shapes/circle.js +57 -0
- package/dist/shapes/clip.d.ts +5 -0
- package/dist/shapes/clip.js +31 -0
- package/dist/shapes/connect.d.ts +16 -0
- package/dist/shapes/connect.js +70 -0
- package/dist/shapes/curve.d.ts +60 -0
- package/dist/shapes/curve.js +285 -0
- package/dist/shapes/dashed.d.ts +16 -0
- package/dist/shapes/dashed.js +142 -0
- package/dist/shapes/debug.d.ts +43 -0
- package/dist/shapes/debug.js +97 -0
- package/dist/shapes/group.d.ts +5 -0
- package/dist/shapes/group.js +10 -0
- package/dist/shapes/handle.d.ts +32 -0
- package/dist/shapes/handle.js +88 -0
- package/dist/shapes/index.d.ts +23 -0
- package/dist/shapes/index.js +23 -0
- package/dist/shapes/interaction.d.ts +32 -0
- package/dist/shapes/interaction.js +187 -0
- package/dist/shapes/label.d.ts +20 -0
- package/dist/shapes/label.js +42 -0
- package/dist/shapes/layout.d.ts +29 -0
- package/dist/shapes/layout.js +74 -0
- package/dist/shapes/line.d.ts +21 -0
- package/dist/shapes/line.js +79 -0
- package/dist/shapes/list.d.ts +18 -0
- package/dist/shapes/list.js +51 -0
- package/dist/shapes/mount.d.ts +7 -0
- package/dist/shapes/mount.js +10 -0
- package/dist/shapes/path.d.ts +77 -0
- package/dist/shapes/path.js +227 -0
- package/dist/shapes/rect.d.ts +30 -0
- package/dist/shapes/rect.js +131 -0
- package/dist/shapes/shape.d.ts +132 -0
- package/dist/shapes/shape.js +306 -0
- package/dist/shapes/text.d.ts +24 -0
- package/dist/shapes/text.js +53 -0
- package/dist/shapes/tokens.d.ts +28 -0
- package/dist/shapes/tokens.js +27 -0
- package/dist/shapes/transitions.d.ts +23 -0
- package/dist/shapes/transitions.js +62 -0
- package/dist/tex/decorations.d.ts +26 -0
- package/dist/tex/decorations.js +116 -0
- package/dist/tex/index.d.ts +5 -0
- package/dist/tex/index.js +5 -0
- package/dist/tex/marker.d.ts +17 -0
- package/dist/tex/marker.js +63 -0
- package/dist/tex/motion.d.ts +43 -0
- package/dist/tex/motion.js +290 -0
- package/dist/tex/parts.d.ts +65 -0
- package/dist/tex/parts.js +149 -0
- package/dist/tex/tex.d.ts +45 -0
- package/dist/tex/tex.js +244 -0
- package/dist/web/attr.d.ts +16 -0
- package/dist/web/attr.js +98 -0
- package/dist/web/diagram.d.ts +49 -0
- package/dist/web/diagram.js +260 -0
- package/dist/web/index.d.ts +6 -0
- package/dist/web/index.js +6 -0
- package/dist/web/md-marker.d.ts +6 -0
- package/dist/web/md-marker.js +39 -0
- package/dist/web/md-tex.d.ts +6 -0
- package/dist/web/md-tex.js +61 -0
- package/dist/web/raf.d.ts +6 -0
- package/dist/web/raf.js +24 -0
- package/dist/web/viewport.d.ts +7 -0
- package/dist/web/viewport.js +13 -0
- package/package.json +87 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// box.ts — reactive axis-aligned rectangle.
|
|
2
|
+
//
|
|
3
|
+
// Invertibles (`add`, `sub`, `scale`, `expand`) return `: this` and ride
|
|
4
|
+
// on `Cell#lens(fwd, bwd)`. Chained calls compose into a lens chain.
|
|
5
|
+
import { tween } from "../anim.js";
|
|
6
|
+
import { Cell, isComputed, lazy, reader, readNow, } from "../signal.js";
|
|
7
|
+
import { derived, field } from "../writable.js";
|
|
8
|
+
import { Bool } from "./bool.js";
|
|
9
|
+
import { Num, num } from "./num.js";
|
|
10
|
+
import { Vec } from "./vec.js";
|
|
11
|
+
export const add = (a, b) => ({ x: a.x + b.x, y: a.y + b.y, w: a.w + b.w, h: a.h + b.h });
|
|
12
|
+
export const sub = (a, b) => ({ x: a.x - b.x, y: a.y - b.y, w: a.w - b.w, h: a.h - b.h });
|
|
13
|
+
export const scale = (a, k) => ({ x: a.x * k, y: a.y * k, w: a.w * k, h: a.h * k });
|
|
14
|
+
export const lerp = (a, b, t) => ({
|
|
15
|
+
x: a.x + (b.x - a.x) * t,
|
|
16
|
+
y: a.y + (b.y - a.y) * t,
|
|
17
|
+
w: a.w + (b.w - a.w) * t,
|
|
18
|
+
h: a.h + (b.h - a.h) * t,
|
|
19
|
+
});
|
|
20
|
+
export const equals = (a, b) => a === b || (a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h);
|
|
21
|
+
/** L2 distance over the flat (x, y, w, h) representation. */
|
|
22
|
+
export const metric = (a, b) => Math.hypot(a.x - b.x, a.y - b.y, a.w - b.w, a.h - b.h);
|
|
23
|
+
export const expand = (b, n) => ({
|
|
24
|
+
x: b.x - n,
|
|
25
|
+
y: b.y - n,
|
|
26
|
+
w: b.w + 2 * n,
|
|
27
|
+
h: b.h + 2 * n,
|
|
28
|
+
});
|
|
29
|
+
export const contains = (b, p) => p.x >= b.x && p.x <= b.x + b.w && p.y >= b.y && p.y <= b.y + b.h;
|
|
30
|
+
/** Closest point inside `b` to `p`. Already-inside is identity; outside
|
|
31
|
+
* snaps to the nearest boundary point. `Box#contains`'s true-side bwd. */
|
|
32
|
+
export const clampToBox = (p, b) => ({
|
|
33
|
+
x: Math.max(b.x, Math.min(b.x + b.w, p.x)),
|
|
34
|
+
y: Math.max(b.y, Math.min(b.y + b.h, p.y)),
|
|
35
|
+
});
|
|
36
|
+
/** Closest point strictly outside `b` to `p`, displaced past the nearest
|
|
37
|
+
* edge by `eps`. Already-outside is identity. `Box#contains`'s
|
|
38
|
+
* false-side bwd. */
|
|
39
|
+
export const ejectFromBox = (p, b, eps = 1e-6) => {
|
|
40
|
+
if (!contains(b, p))
|
|
41
|
+
return p;
|
|
42
|
+
const dLeft = p.x - b.x;
|
|
43
|
+
const dRight = b.x + b.w - p.x;
|
|
44
|
+
const dTop = p.y - b.y;
|
|
45
|
+
const dBot = b.y + b.h - p.y;
|
|
46
|
+
const min = Math.min(dLeft, dRight, dTop, dBot);
|
|
47
|
+
if (min === dLeft)
|
|
48
|
+
return { x: b.x - eps, y: p.y };
|
|
49
|
+
if (min === dRight)
|
|
50
|
+
return { x: b.x + b.w + eps, y: p.y };
|
|
51
|
+
if (min === dTop)
|
|
52
|
+
return { x: p.x, y: b.y - eps };
|
|
53
|
+
return { x: p.x, y: b.y + b.h + eps };
|
|
54
|
+
};
|
|
55
|
+
/** Bounding box around a set of boxes. */
|
|
56
|
+
export function union(...bs) {
|
|
57
|
+
if (bs.length === 0)
|
|
58
|
+
return { x: 0, y: 0, w: 0, h: 0 };
|
|
59
|
+
let xMin = bs[0].x, yMin = bs[0].y;
|
|
60
|
+
let xMax = xMin + bs[0].w, yMax = yMin + bs[0].h;
|
|
61
|
+
for (let i = 1; i < bs.length; i++) {
|
|
62
|
+
const o = bs[i];
|
|
63
|
+
if (o.x < xMin)
|
|
64
|
+
xMin = o.x;
|
|
65
|
+
if (o.y < yMin)
|
|
66
|
+
yMin = o.y;
|
|
67
|
+
if (o.x + o.w > xMax)
|
|
68
|
+
xMax = o.x + o.w;
|
|
69
|
+
if (o.y + o.h > yMax)
|
|
70
|
+
yMax = o.y + o.h;
|
|
71
|
+
}
|
|
72
|
+
return { x: xMin, y: yMin, w: xMax - xMin, h: yMax - yMin };
|
|
73
|
+
}
|
|
74
|
+
/** Perimeter point on a Box facing `toward`. Default `Shape.boundary`. */
|
|
75
|
+
export function edgeFrom(b, toward) {
|
|
76
|
+
const cx = b.x + b.w / 2;
|
|
77
|
+
const cy = b.y + b.h / 2;
|
|
78
|
+
const dx = toward.x - cx;
|
|
79
|
+
const dy = toward.y - cy;
|
|
80
|
+
if (dx === 0 && dy === 0)
|
|
81
|
+
return { x: cx, y: cy };
|
|
82
|
+
const k = Math.min(dx === 0 ? Number.POSITIVE_INFINITY : b.w / 2 / Math.abs(dx), dy === 0 ? Number.POSITIVE_INFINITY : b.h / 2 / Math.abs(dy));
|
|
83
|
+
return { x: cx + dx * k, y: cy + dy * k };
|
|
84
|
+
}
|
|
85
|
+
const linearImpl = { add, sub, scale };
|
|
86
|
+
const packImpl = {
|
|
87
|
+
dim: 4,
|
|
88
|
+
read: (v, a, o) => {
|
|
89
|
+
a[o] = v.x;
|
|
90
|
+
a[o + 1] = v.y;
|
|
91
|
+
a[o + 2] = v.w;
|
|
92
|
+
a[o + 3] = v.h;
|
|
93
|
+
},
|
|
94
|
+
write: (a, o) => ({ x: a[o], y: a[o + 1], w: a[o + 2], h: a[o + 3] }),
|
|
95
|
+
};
|
|
96
|
+
export class Box extends Cell {
|
|
97
|
+
static traits = {
|
|
98
|
+
linear: linearImpl,
|
|
99
|
+
lerp,
|
|
100
|
+
metric,
|
|
101
|
+
equals,
|
|
102
|
+
pack: packImpl,
|
|
103
|
+
};
|
|
104
|
+
constructor(v = { x: 0, y: 0, w: 0, h: 0 }) {
|
|
105
|
+
super(v, { equals });
|
|
106
|
+
}
|
|
107
|
+
add(b) {
|
|
108
|
+
const bf = reader(b);
|
|
109
|
+
return this.lens(v => add(v, bf()), n => sub(n, bf()));
|
|
110
|
+
}
|
|
111
|
+
sub(b) {
|
|
112
|
+
const bf = reader(b);
|
|
113
|
+
return this.lens(v => sub(v, bf()), n => add(n, bf()));
|
|
114
|
+
}
|
|
115
|
+
scale(k) {
|
|
116
|
+
const kf = reader(k);
|
|
117
|
+
return this.lens(v => scale(v, kf()), n => scale(n, 1 / kf()));
|
|
118
|
+
}
|
|
119
|
+
expand(n) {
|
|
120
|
+
const nf = reader(n);
|
|
121
|
+
return this.lens(v => expand(v, nf()), o => expand(o, -nf()));
|
|
122
|
+
}
|
|
123
|
+
lerp(b, t) {
|
|
124
|
+
return Box.derive(() => lerp(this.value, readNow(b), readNow(t)));
|
|
125
|
+
}
|
|
126
|
+
/** Membership predicate. Conditional return type: a writable `Vec`
|
|
127
|
+
* yields `Writable<Bool>` and flipping the view moves the source —
|
|
128
|
+
* `true` clamps to the nearest in-box point, `false` ejects past the
|
|
129
|
+
* nearest edge by `eps`. Literal / RO inputs yield a bare RO `Bool`. */
|
|
130
|
+
contains(p) {
|
|
131
|
+
if (p instanceof Vec) {
|
|
132
|
+
// A computed Vec has no backward path → RO branch; sources and
|
|
133
|
+
// writable lenses accept write-back.
|
|
134
|
+
if (!isComputed(p)) {
|
|
135
|
+
// `.bind(Bool)` + cast steps past the generic overloads, whose
|
|
136
|
+
// mapped-tuple inference over the full class types otherwise blows
|
|
137
|
+
// the instantiation depth.
|
|
138
|
+
const mk = Bool.lens.bind(Bool);
|
|
139
|
+
return mk([this, p], vals => contains(vals[0], vals[1]), (target, vals) => {
|
|
140
|
+
const [b, v] = vals;
|
|
141
|
+
if (contains(b, v) === target)
|
|
142
|
+
return [undefined, undefined];
|
|
143
|
+
return [undefined, target ? clampToBox(v, b) : ejectFromBox(v, b)];
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return Bool.derive(() => contains(this.value, readNow(p)));
|
|
148
|
+
}
|
|
149
|
+
get x() {
|
|
150
|
+
return field(this, "x", Num);
|
|
151
|
+
}
|
|
152
|
+
get y() {
|
|
153
|
+
return field(this, "y", Num);
|
|
154
|
+
}
|
|
155
|
+
get w() {
|
|
156
|
+
return field(this, "w", Num);
|
|
157
|
+
}
|
|
158
|
+
get h() {
|
|
159
|
+
return field(this, "h", Num);
|
|
160
|
+
}
|
|
161
|
+
get area() {
|
|
162
|
+
return derived(this, "area", Num, b => b.w * b.h);
|
|
163
|
+
}
|
|
164
|
+
/** Vec at parametric (u, v) within `[0,1]²`. Not memoised (arbitrary
|
|
165
|
+
* pairs would leak a cache entry each) — use the named edge getters
|
|
166
|
+
* (`.center`, `.top`, …) for stable identity. */
|
|
167
|
+
at(u, v) {
|
|
168
|
+
return Vec.derive(this, b => ({ x: b.x + u * b.w, y: b.y + v * b.h }));
|
|
169
|
+
}
|
|
170
|
+
// Named edges — RO views over `at(u, v)`, memoised under stable keys
|
|
171
|
+
// so subscribers always see the same Vec. `lazy()` directly since
|
|
172
|
+
// `at()` already returns a Vec.
|
|
173
|
+
get center() {
|
|
174
|
+
return lazy(this, "center", () => this.at(0.5, 0.5));
|
|
175
|
+
}
|
|
176
|
+
get top() {
|
|
177
|
+
return lazy(this, "top", () => this.at(0.5, 0));
|
|
178
|
+
}
|
|
179
|
+
get bottom() {
|
|
180
|
+
return lazy(this, "bottom", () => this.at(0.5, 1));
|
|
181
|
+
}
|
|
182
|
+
get left() {
|
|
183
|
+
return lazy(this, "left", () => this.at(0, 0.5));
|
|
184
|
+
}
|
|
185
|
+
get right() {
|
|
186
|
+
return lazy(this, "right", () => this.at(1, 0.5));
|
|
187
|
+
}
|
|
188
|
+
/** Tween-builder, implied by the lerp trait. */
|
|
189
|
+
to(target, dur, ease) {
|
|
190
|
+
return tween(this, target, dur, ease);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/** Writable `Box` at `(x, y, w, h)`. Each component is a literal `number`
|
|
194
|
+
* (lifted to a fresh seed) or an existing `Writable<Num>` (identity
|
|
195
|
+
* passthrough). RO sources are rejected at the type level — use
|
|
196
|
+
* `Box.derive(...)` for reactive RO tracking, or `cell.value` to
|
|
197
|
+
* snapshot. Lock a component with `Num.pin(c)`. */
|
|
198
|
+
export function box(x = 0, y = 0, w = 0, h = 0) {
|
|
199
|
+
if (typeof x === "number" &&
|
|
200
|
+
typeof y === "number" &&
|
|
201
|
+
typeof w === "number" &&
|
|
202
|
+
typeof h === "number") {
|
|
203
|
+
return new Box({ x, y, w, h });
|
|
204
|
+
}
|
|
205
|
+
const xN = num(x);
|
|
206
|
+
const yN = num(y);
|
|
207
|
+
const wN = num(w);
|
|
208
|
+
const hN = num(h);
|
|
209
|
+
// The view fully reconstructs all 4 axes (1-arg bwd ⇒ no source read).
|
|
210
|
+
return Box.lens([xN, yN, wN, hN], ([bx, by, bw, bh]) => ({ x: bx, y: by, w: bw, h: bh }), v => [v.x, v.y, v.w, v.h]);
|
|
211
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Cell, type Val, type Writable } from "../signal.js";
|
|
2
|
+
import { Bool } from "./bool.js";
|
|
3
|
+
import { Color } from "./color.js";
|
|
4
|
+
import { Spring, type SpringOpts } from "./gpu.js";
|
|
5
|
+
import { Vec } from "./vec.js";
|
|
6
|
+
/** Raster header. The graph compares `epoch`; `tex` is an RGBA32F texture in
|
|
7
|
+
* the shared GL context (channels 0–1, may overshoot mid-deconvolution). */
|
|
8
|
+
export interface Raster {
|
|
9
|
+
readonly tex: WebGLTexture;
|
|
10
|
+
readonly w: number;
|
|
11
|
+
readonly h: number;
|
|
12
|
+
readonly epoch: number;
|
|
13
|
+
}
|
|
14
|
+
type V = Raster;
|
|
15
|
+
/** Stamp a texture with a fresh epoch — the only way to mint a value. */
|
|
16
|
+
export declare const stamp: (tex: WebGLTexture, w: number, h: number) => V;
|
|
17
|
+
export declare const equals: (a: V, b: V) => boolean;
|
|
18
|
+
export declare class Canvas extends Cell<V> {
|
|
19
|
+
static traits: {
|
|
20
|
+
equals: (a: V, b: V) => boolean;
|
|
21
|
+
};
|
|
22
|
+
readonly _t: typeof Canvas.traits;
|
|
23
|
+
constructor(v?: V);
|
|
24
|
+
/** Per-channel invert (alpha preserved). Involution. */
|
|
25
|
+
invert(): this;
|
|
26
|
+
/** Horizontal flip. Involution. */
|
|
27
|
+
flipH(): this;
|
|
28
|
+
/** Multiply RGB by reactive `k` (alpha preserved). Invertible while
|
|
29
|
+
* k ≠ 0. */
|
|
30
|
+
brightness(k: Val<number>): this;
|
|
31
|
+
/** Grayscale (Rec.601 luma) view; complement is the per-pixel chroma
|
|
32
|
+
* residual `(r−Y, g−Y, b−Y)`, so editing the gray view recolours the
|
|
33
|
+
* source. The raster analog of `str.lowercase()`. */
|
|
34
|
+
grayscale(): Writable<Canvas>;
|
|
35
|
+
/** Chroma view (the dual of `grayscale`): `(r−Y, g−Y, b−Y)` on a mid-grey
|
|
36
|
+
* base, complement is the luma `Y`. Editing the colour re-lights nothing —
|
|
37
|
+
* it rewrites hue while keeping the original brightness. */
|
|
38
|
+
chroma(): Writable<Canvas>;
|
|
39
|
+
/** Sub-rectangle view (reactive `x,y,w,h`). Editing the crop composites
|
|
40
|
+
* back into the source; the surround reads straight from the parent. */
|
|
41
|
+
crop(x: Val<number>, y: Val<number>, w: Val<number>, h: Val<number>): Writable<Canvas>;
|
|
42
|
+
/** Box-downsampled thumbnail (integer `factor`). Complement is the
|
|
43
|
+
* Laplacian residual `source − up(down(source))`; editing the thumbnail
|
|
44
|
+
* reconstructs full-res detail on top of the edit. */
|
|
45
|
+
downsample(factor: number): Writable<Canvas>;
|
|
46
|
+
/** Gaussian blur (reactive `radius`). Writable: the backward direction
|
|
47
|
+
* runs an iterated Richardson–Lucy deconvolution seeded from the source.
|
|
48
|
+
* Each step is `x ← x · H(target / H(x))`, non-negative and multiplicative,
|
|
49
|
+
* so untouched regions stay fixed (their ratio is 1) while a stroke
|
|
50
|
+
* back-solves to a sharp pre-image with far less ringing than an additive
|
|
51
|
+
* solve. PutGet, not exact GetPut — the residual is the honest signature
|
|
52
|
+
* of an ill-posed inverse. */
|
|
53
|
+
blur(radius: Val<number>): this;
|
|
54
|
+
/** Mean colour (0–1) as a writable `Color`; the GPU reduces, the write
|
|
55
|
+
* shifts every pixel by the delta (a rigid translate in RGB). */
|
|
56
|
+
meanColor(): Writable<Color>;
|
|
57
|
+
/** Mean luma ≥ reactive `threshold` (0–1) as a writable `Bool`; flipping
|
|
58
|
+
* the bit auto-exposes — iterate the gain (clipping caps a single step)
|
|
59
|
+
* until the mean crosses the line. */
|
|
60
|
+
brighterThan(threshold: Val<number>): Writable<Bool>;
|
|
61
|
+
/** Dimensions `(w, h)` as a read-only `Vec`. */
|
|
62
|
+
get dimensions(): Vec;
|
|
63
|
+
/** A GPU per-pixel spring driver seeded from this value's texture. The
|
|
64
|
+
* host steps it and writes `current()` back into a root cell each frame;
|
|
65
|
+
* settle is the GPU energy reduction. */
|
|
66
|
+
spring(opts?: SpringOpts): Spring;
|
|
67
|
+
}
|
|
68
|
+
/** Writable `Canvas` of size `w×h`. `painter` fills it pixel-by-pixel
|
|
69
|
+
* (RGBA, 0–255); omit for transparent black. Uploaded once to a texture. */
|
|
70
|
+
export declare function canvas(w: number, h: number, painter?: (x: number, y: number) => readonly [number, number, number, number]): Writable<Canvas>;
|
|
71
|
+
export {};
|