@weasel-js/core 1.4.3 → 1.4.4
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/CHANGELOG.md +367 -0
- package/dist/{pointSnapToGrid-D1bRdq-j.d.ts → autoPoseDescriptor-DF1SnnSx.d.ts} +18 -3
- package/dist/{builtins-CtGORLCG.d.ts → builtins-BXFBXegF.d.ts} +200 -100
- package/dist/{chunk-ORZNKVXM.js → chunk-2VXGHUVL.js} +3 -3
- package/dist/{chunk-ORZNKVXM.js.map → chunk-2VXGHUVL.js.map} +1 -1
- package/dist/{chunk-LEURURX3.js → chunk-BL65SHCX.js} +17 -5
- package/dist/chunk-BL65SHCX.js.map +1 -0
- package/dist/{chunk-BLJNRMKB.js → chunk-PRGBGMH3.js} +3 -3
- package/dist/{chunk-BLJNRMKB.js.map → chunk-PRGBGMH3.js.map} +1 -1
- package/dist/{chunk-WYPSGIYS.js → chunk-R3AWPTLZ.js} +1773 -1209
- package/dist/chunk-R3AWPTLZ.js.map +1 -0
- package/dist/{chunk-SBFC6J3C.js → chunk-WPM42WJP.js} +3 -3
- package/dist/{chunk-SBFC6J3C.js.map → chunk-WPM42WJP.js.map} +1 -1
- package/dist/clipboard.d.ts +2 -2
- package/dist/clone.d.ts +2 -2
- package/dist/{geometry-CHR36Ub_.d.ts → geometry-6fCNhAux.d.ts} +1 -1
- package/dist/{grid-Bw8cSde-.d.ts → grid-0Pbn5B2C.d.ts} +1 -14
- package/dist/index.d.ts +231 -74
- package/dist/index.js +5 -5
- package/dist/insert.d.ts +3 -3
- package/dist/insert.js +1 -1
- package/dist/move.d.ts +4 -4
- package/dist/move.js +2 -2
- package/dist/{options-DYfUlZxk.d.ts → options-DbYLImvq.d.ts} +1 -1
- package/dist/{registry-DnoTWGED.d.ts → registry-BY-wI9gm.d.ts} +4 -4
- package/dist/renderer.d.ts +2 -2
- package/dist/renderer.js +5 -5
- package/dist/resize.d.ts +5 -4
- package/dist/resize.js +2 -2
- package/dist/routing.d.ts +5 -5
- package/dist/routing.js +1 -1
- package/dist/{types-CoVTbo_y.d.ts → types-DEALFt5F.d.ts} +1 -6
- package/dist/{types-H7o6MaPo.d.ts → types-bcc7jcUy.d.ts} +96 -14
- package/dist/{types-BJqsTlXl.d.ts → types-ei3UMl9R.d.ts} +1 -1
- package/package.json +9 -9
- package/dist/chunk-LEURURX3.js.map +0 -1
- package/dist/chunk-WYPSGIYS.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,372 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9ce6f00: Fix solid fills coming out multiplied by whatever bitmap shared their batch.
|
|
8
|
+
A solid vertex carried the UV of a 1x1 white texel, but the flush bound the
|
|
9
|
+
run's *image*, so any solid staged alongside an image quad sampled that bitmap
|
|
10
|
+
at its middle texel instead. A wall of thumbnails is a ground rect under an
|
|
11
|
+
atlas quad per cell — the shape the merged batch exists for — so its grounds
|
|
12
|
+
came out tinted by the atlas: white drew olive. Reported from outside the repo
|
|
13
|
+
against a canvas2d reference; no visual baseline caught it, because in every
|
|
14
|
+
demo the quad covers its ground.
|
|
15
|
+
|
|
16
|
+
Every batch vertex now names the texture slot it samples. Slot 0 is always the
|
|
17
|
+
white texel, so a solid's `texture() * a_vertexColor` is the vertex color
|
|
18
|
+
exactly whatever else joins its run, and bitmaps take the slots above it.
|
|
19
|
+
|
|
20
|
+
That also lets one run hold up to seven distinct bitmaps. A document with a
|
|
21
|
+
handful of loose images used to break its run on every change of bitmap; now it
|
|
22
|
+
breaks only when the slots run out, or when one bitmap is drawn at two
|
|
23
|
+
MAG_FILTERs, which is state on the texture object and cannot be had both ways
|
|
24
|
+
in one draw.
|
|
25
|
+
|
|
26
|
+
`tests/visual/batch-pixels.spec.ts` reads the framebuffer channel by channel
|
|
27
|
+
rather than diffing a screenshot, which is what it takes to see a run's
|
|
28
|
+
composition at all.
|
|
29
|
+
- 6f876a7: Two canvases under one `DepRegistryProvider` no longer take each other's deps
|
|
30
|
+
down.
|
|
31
|
+
|
|
32
|
+
`register` set one source per name and its release did a bare `delete`. Mount a
|
|
33
|
+
second canvas under a shared provider and it displaced the first's `view` /
|
|
34
|
+
`scene` / `selection`; unmount either one and the name went dark for the canvas
|
|
35
|
+
still on screen.
|
|
36
|
+
|
|
37
|
+
Sources now stack per name, newest live, and a release removes its own entry
|
|
38
|
+
wherever it sits — so a displaced source comes back when the one above it
|
|
39
|
+
leaves, and a displaced source leaving disturbs nothing. Same shape as the
|
|
40
|
+
`ActionsProvider` registrant stack, one layer down.
|
|
41
|
+
- ed400a3: A derivation now receives its dependencies as `{ node, pose }` rather than as
|
|
42
|
+
bare poses. Breaking for anything with a `derivePath` or `derivePose`: read
|
|
43
|
+
`deps[0]?.pose` where it read `deps[0]`.
|
|
44
|
+
|
|
45
|
+
A connector legitimately reads more than a box — one that thickens with its
|
|
46
|
+
endpoint's weight, or routes only to nodes on a given layer, is answering off
|
|
47
|
+
`data` and `layer`. The scene has invalidated dependents on `kit:setData` and
|
|
48
|
+
`kit:setLayer` since those landed, and `scene.ts` said in a comment that a
|
|
49
|
+
derivation "is handed its dependencies' nodes, not only their poses". It was
|
|
50
|
+
not: the invalidation was paying for a read the signature could not perform.
|
|
51
|
+
|
|
52
|
+
`scenePoseLookup` is now `sceneDepLookup` and answers `DerivedDep` for the same
|
|
53
|
+
reason. `DerivedDep` is exported.
|
|
54
|
+
- fc00dae: Hand a derivation its dependencies' paths, and label an edge with one.
|
|
55
|
+
|
|
56
|
+
`DerivedDep` is now `{ node, pose, path }`. The path resolves on first read and
|
|
57
|
+
memoizes, so a route costs the same whether one node reads it or five, and a
|
|
58
|
+
dependency nobody asks about costs nothing. `resolveDerivedPath` moves beside
|
|
59
|
+
`derivedPose` in `core/scene` — a pose can now derive from a dependency's path —
|
|
60
|
+
and picks up the cycle guard the pose side already had.
|
|
61
|
+
|
|
62
|
+
`pointAlongPath(path, t)` is the new geometry primitive underneath: where a path
|
|
63
|
+
is at a fraction of its length, and which way it heads there, measured along the
|
|
64
|
+
flattened arc.
|
|
65
|
+
|
|
66
|
+
In `@weasel-js/diagram`, an edge label is an ordinary leaf node with
|
|
67
|
+
`dependsOn: [edge]` and `LABEL_DERIVE_POSE`. Its trait says where it sits —
|
|
68
|
+
`at: 'start' | 'mid' | 'end'` or a fraction, plus an `offset` perpendicular to
|
|
69
|
+
the route — and it reads the edge's resolved path rather than routing again, so
|
|
70
|
+
a label and its arrowhead can never disagree about where the edge went.
|
|
71
|
+
- 730da55: A derived node now recomputes when a dependency's `data` or `layer` changes.
|
|
72
|
+
|
|
73
|
+
`derivePath` is handed its dependencies' nodes, not only their poses — so a
|
|
74
|
+
connector that thickens with a node's weight, or draws only for nodes on a given
|
|
75
|
+
layer, is answering off `data` and `layer`. `kit:setPose` and `kit:move`
|
|
76
|
+
invalidated the dependent's memo; `kit:setData` and `kit:setLayer` did not, so
|
|
77
|
+
the derived geometry kept the old answer with nothing on screen to show it was
|
|
78
|
+
stale. Undo and redo were wrong the same way.
|
|
79
|
+
|
|
80
|
+
Both ops now invalidate dependents on `apply` and on `revert`, matching the two
|
|
81
|
+
that already did.
|
|
82
|
+
- 60ba9d9: A stroke marker on a derived path is drawn.
|
|
83
|
+
|
|
84
|
+
`markerStart` / `markerMid` / `markerEnd` reached the `kit:derived` painter
|
|
85
|
+
intact and were then dropped: the painter emitted its stroke command and
|
|
86
|
+
returned, where `kit:path` follows with a marker pass. So an arrowhead on a
|
|
87
|
+
diagram edge — the whole reason markers and derived geometry landed in the same
|
|
88
|
+
release — silently drew nothing. Its own `ink` had been reserving the hit-test
|
|
89
|
+
reach for the marker all along, which is the shape of the bug: the pointer could
|
|
90
|
+
already grab past the end of a line with no head on it.
|
|
91
|
+
|
|
92
|
+
A connect-authored edge now carries `markerEnd: 'arrow'` by default. An edge
|
|
93
|
+
runs *from* one node *to* another and a plain line does not say so;
|
|
94
|
+
`DEFAULT_EDGE_STROKE` is exported for a consumer overriding `commit` who wants
|
|
95
|
+
the rest of it.
|
|
96
|
+
- 5732951: The minimap's scene fit and the scene text editor read a derived pose rather
|
|
97
|
+
than the placeholder a derived node authors. `computeFitView`'s `'scene'` fit
|
|
98
|
+
frames on `documentPose`, so a derived node is framed where it actually is
|
|
99
|
+
while a drag still leaves the framing alone; `useSceneTextEdit` resolves both
|
|
100
|
+
its double-click hit test and the overlay's own projection through
|
|
101
|
+
`effectivePose`, so double-clicking a derived label opens the editor on it and
|
|
102
|
+
the box lands on the text.
|
|
103
|
+
|
|
104
|
+
Removes `UseMoveOptions.cascadeWorldPose`. Nothing has read it since the move
|
|
105
|
+
action started walking `scene.childrenOf` for its own cascade — it was a
|
|
106
|
+
documented option that silently did nothing, and two doc comments described the
|
|
107
|
+
behavior it used to drive.
|
|
108
|
+
- 2ff4824: A scene node can now derive its **pose** from its dependencies, the way it
|
|
109
|
+
already derived its path. New API; a group's bounds change behavior.
|
|
110
|
+
|
|
111
|
+
`Node.derivePose` takes the same `dependsOn` list as `derivePath`, serializes
|
|
112
|
+
through `SceneRegistry.derivePose` by key, and rides the same push
|
|
113
|
+
invalidation. Where a derived path is resolved at paint time and reaches only
|
|
114
|
+
the painter, a derived pose is what the node *is* at — it feeds bounds,
|
|
115
|
+
hit-testing, selection chrome, snapping and layout.
|
|
116
|
+
|
|
117
|
+
`dependsOn` gains a second form, `'children'`: "my own children, in child
|
|
118
|
+
order", which a fixed id list cannot express because reparenting would have to
|
|
119
|
+
maintain it. The two forms differ in lifetime as well as membership — deleting
|
|
120
|
+
a node still deletes everything that names it in `dependsOn`, but a container
|
|
121
|
+
outlives the children it derives from, because an emptied group is still a
|
|
122
|
+
group.
|
|
123
|
+
|
|
124
|
+
`groupAction` uses it, which fixes the group-bounds defect: a container's union
|
|
125
|
+
AABB was computed once at creation and never re-derived, so moving a member
|
|
126
|
+
left the group's bounds, selection chrome and hit area behind. The kit
|
|
127
|
+
registers the union function under `kit:unionOfChildren` and merges its own
|
|
128
|
+
registry entries under the consumer's, so a grouped document round-trips
|
|
129
|
+
through `toJSON` in any scene.
|
|
130
|
+
|
|
131
|
+
`effectivePose(scene, node)` is the one rule — override, else derived, else
|
|
132
|
+
authored — and now takes the scene rather than the override table alone. The
|
|
133
|
+
three render walks, the pick walk, and the scene, commit and gesture adapters
|
|
134
|
+
all resolve through it or through `documentPose`, the same answer minus the
|
|
135
|
+
override step for a reader that must not see an in-flight gesture. Both are
|
|
136
|
+
exported.
|
|
137
|
+
|
|
138
|
+
`clipFromPose`, `derivePath` and `derivePose` now share one table-driven
|
|
139
|
+
serialization path (`core/scene/nodeFnFields.ts`) instead of a copy per field.
|
|
140
|
+
- 3d89141: Layout: `layered`, `tree` and `force`, and the action that runs one.
|
|
141
|
+
|
|
142
|
+
A layout is a plain function of the graph — no scene, no ops, no history. It
|
|
143
|
+
hands back the new top-left for every node that **moves**, and a node already
|
|
144
|
+
standing where the layout wants it is absent from the answer, so re-running a
|
|
145
|
+
layout on an arrangement it produced writes nothing and pushes no undo entry.
|
|
146
|
+
|
|
147
|
+
Three rules keep a re-layout from scrambling a diagram someone has arranged.
|
|
148
|
+
There is no RNG anywhere in the path, so the same graph always lays out the same
|
|
149
|
+
way. Within-rank order is seeded from where the nodes already sit on the cross
|
|
150
|
+
axis rather than from crossing-minimization, so two branches an author dragged
|
|
151
|
+
into an order come back in it. And a node carrying `pinned: true` never moves,
|
|
152
|
+
with the rest of the layout translated to sit around it — with no pin, the
|
|
153
|
+
layout lands on the diagram's own bounding box rather than at the origin.
|
|
154
|
+
|
|
155
|
+
`layered` ranks by longest path, breaking cycles with a depth-first walk in node
|
|
156
|
+
order so a loop draws as an edge running back up the page. `tree` centers a
|
|
157
|
+
parent over its children's block; a graph that is not a tree still lays out,
|
|
158
|
+
since roots are the nodes nothing points at and anything the walk cannot reach
|
|
159
|
+
becomes a root of its own. `force` is an iterative relaxation seeded from the
|
|
160
|
+
current positions — **the one layout that is not idempotent**, since re-running
|
|
161
|
+
it keeps relaxing.
|
|
162
|
+
|
|
163
|
+
`buildGraph` reads the adjacency index from the same participant source the port
|
|
164
|
+
affordance takes, per invocation rather than maintaining one. `createLayoutAction`
|
|
165
|
+
rebuilds it on each press and writes the whole move as a single `scene.batch`,
|
|
166
|
+
carrying a container's whole subtree — `setPose` does not cascade, and a built
|
|
167
|
+
body would otherwise walk out from under its own label rows.
|
|
168
|
+
|
|
169
|
+
In core, `createSimulation` is the velocity-Verlet integrator with no clock
|
|
170
|
+
attached: `tick()` is the only thing that moves a node, so a pure function can
|
|
171
|
+
run a whole relaxation and read the result. `useSimulation` is now that
|
|
172
|
+
integrator on a frame loop and is otherwise unchanged. `SimulationCore` and
|
|
173
|
+
`SimulationOptions` name the halves, and forces can be handed a seeded `random`
|
|
174
|
+
in place of `Math.random`.
|
|
175
|
+
- 4a128c4: New package `@weasel-js/diagram` — the skeleton of weasel's node-link
|
|
176
|
+
diagramming: flowcharts, pipelines, code-flow diagrams, simple visual
|
|
177
|
+
programming. Arc 3 of the diagram design; edges, routing, the connect gesture
|
|
178
|
+
and layout are still to come.
|
|
179
|
+
|
|
180
|
+
**`DiagramNode` is a trait on an existing scene node, not a node type the
|
|
181
|
+
package mints.** A text block, an image, a path, a group or a plain rect all
|
|
182
|
+
become participants by carrying it, and nothing has to be authored through this
|
|
183
|
+
package to take part. Two ways to attach it, both answered by the default
|
|
184
|
+
reader: on the node's own `data.diagram`, or by kind — `createDiagramNodes`
|
|
185
|
+
takes predicates over `data` the way `createNodeRouting` does, so a class of
|
|
186
|
+
node takes part without being stamped one at a time.
|
|
187
|
+
|
|
188
|
+
**Ports default to the perimeter, so a node needs to say nothing to be
|
|
189
|
+
connectable.** `portsOf(node, pose)` resolves every port to a world point and
|
|
190
|
+
an outward normal, reading bounds through the pose descriptor and carrying the
|
|
191
|
+
node's rotation. Anchors are normalized against the bounds — `{ u, v }` from
|
|
192
|
+
the top-left — so a port stays where it was put when the node is resized.
|
|
193
|
+
|
|
194
|
+
**The body builder is optional**, for nodes that should look like a flowchart
|
|
195
|
+
box: `rect`, `diamond`, `stadium` and `parallelogram` outlines plus a `Row[]`
|
|
196
|
+
body of labels, fields, port rows and slots. Rows measure a floor, and the
|
|
197
|
+
authored pose is maxed against it rather than set to it — adding a row can grow
|
|
198
|
+
a node, nothing shrinks one back — which is what keeps resize, align,
|
|
199
|
+
distribute, guides, snapping and undo free of a special case. Text measurement
|
|
200
|
+
is a seam rather than an import; `canvasMeasure` adapts a 2D context.
|
|
201
|
+
|
|
202
|
+
Rows lay out in the shape's **content box**, not its bounding box.
|
|
203
|
+
`contentBox` reports the largest axis-aligned box inside an outline — a
|
|
204
|
+
diamond's inscribed rect, a parallelogram minus its lean, the flat span between
|
|
205
|
+
a stadium's ends — and `boxForContent` inverts it so the floor grows to suit.
|
|
206
|
+
Without it a diamond's label is placed against the bounding box, lands outside
|
|
207
|
+
the diamond, and the silhouette clip removes it: the label simply vanishes.
|
|
208
|
+
|
|
209
|
+
`registerDiagramShape` paints a node whose trait names an outline, and reports
|
|
210
|
+
the outline as its silhouette so picking and clipping follow the diamond rather
|
|
211
|
+
than its box. Rows are not painted there — a built body's rows are ordinary
|
|
212
|
+
scene nodes, so the kit's own text painter draws them and text editing,
|
|
213
|
+
selection and styling work on them unchanged.
|
|
214
|
+
|
|
215
|
+
Core exports `AUTO_POSE_DESCRIPTOR` and `isPathLike`, which were already
|
|
216
|
+
general-purpose but reachable only from inside the package. A peer package
|
|
217
|
+
computing a node's bounds needs the kit's own default descriptor rather than a
|
|
218
|
+
second copy of it.
|
|
219
|
+
- aee9d92: `createPoseOverrides` is public.
|
|
220
|
+
|
|
221
|
+
`Scene` is public and its `overrides: PoseOverrides<TPose>` is mandatory — and
|
|
222
|
+
load-bearing, since every ongoing gesture writes a frame to it. The factory that
|
|
223
|
+
builds one was internal, so a consumer assembling a scene-like object by hand
|
|
224
|
+
had to reimplement the table from its type. It is now exported alongside
|
|
225
|
+
`createScene`.
|
|
226
|
+
- c067221: Put every baked gradient ramp in one texture, a row each, rather than a texture
|
|
227
|
+
each. `GradientRampAtlas` replaces `GradientRampCache`: a stop list is baked
|
|
228
|
+
once into a 256-texel strip and written to a row, and the fragment shader picks
|
|
229
|
+
its row with `u_rampV`. Every gradient in a frame now samples the same texture
|
|
230
|
+
unit, which is what a gradient needs before it can take a batch texture slot
|
|
231
|
+
the way a bitmap or a font atlas already does.
|
|
232
|
+
|
|
233
|
+
The atlas doubles from 16 rows and stops at 1024, recycling the least recently
|
|
234
|
+
used row past that. An animating gradient mints a new stop list every frame, so
|
|
235
|
+
the old cache grew a GL texture per frame and freed none of them; the cap is
|
|
236
|
+
what bounds that.
|
|
237
|
+
|
|
238
|
+
`PaintBindContext.bindRamp` now returns the `v` its ramp sits at. A registered
|
|
239
|
+
paint kind that samples the ramp at a constant `v` reads whatever gradient
|
|
240
|
+
happens to own that row, so it must sample at the returned value.
|
|
241
|
+
- 26d40bf: Fold gradients into the shared batch. A gradient fill used to bind its own
|
|
242
|
+
program and break the run of solid geometry, image quads and glyphs around it;
|
|
243
|
+
now it stages alongside them, so a page of gradient-filled shapes is one draw
|
|
244
|
+
rather than one per shape.
|
|
245
|
+
|
|
246
|
+
All three kinds go, and for the same reason — not that the ramp position is
|
|
247
|
+
affine in position, which is true only of a linear gradient, but that the
|
|
248
|
+
*coordinate* the ramp position is computed from is affine in all three. So a
|
|
249
|
+
vertex carries that and the rasterizer's interpolation across a triangle is
|
|
250
|
+
exact. A linear gradient's coordinate is the ramp position itself, which is why
|
|
251
|
+
it needs no paint mode of its own; a radial or conic one carries a
|
|
252
|
+
gradient-space point, with its atlas row where a plain vertex keeps its alpha,
|
|
253
|
+
and the shader takes a `length` or an `atan` of it behind a branch on the flat
|
|
254
|
+
paint mode. Fill opacity and group alpha ride the vertices the way a solid's
|
|
255
|
+
already did, and fills, stroke ribbons and glyph-outline meshes all take the
|
|
256
|
+
route.
|
|
257
|
+
|
|
258
|
+
Per-vertex-colored and even-odd fills still take their own draw, as do patterns
|
|
259
|
+
and shaders.
|
|
260
|
+
|
|
261
|
+
The ramp atlas is what makes the slot arithmetic work: every gradient in a run
|
|
262
|
+
shares one texture slot, so a document full of them costs the same one slot a
|
|
263
|
+
single gradient does. Growing the atlas moves every row, so a bake that would
|
|
264
|
+
grow it — or recycle a row — flushes the run first.
|
|
265
|
+
|
|
266
|
+
Gradient fills now apply the group's color matrix. `gradFill` was the only
|
|
267
|
+
paint program that did not, and since the batch program applies it to
|
|
268
|
+
everything in a run, leaving it out would have made a linear gradient and a
|
|
269
|
+
radial one under the same group paint differently.
|
|
270
|
+
- b8d2940: Layout you can watch, and push against.
|
|
271
|
+
|
|
272
|
+
`usePoseRun` is the transport: each frame it asks a producer for poses,
|
|
273
|
+
publishes them to the scene's ephemeral override channel — the one a drag
|
|
274
|
+
already writes to, which `effectivePose`, derived geometry and the pick source
|
|
275
|
+
read — and commits the lot as one batch when the producer says it is done or
|
|
276
|
+
the consumer stops it. Cancel drops the frames and the document is untouched.
|
|
277
|
+
It runs behind `useVisibleRaf`, and it knows nothing about layout.
|
|
278
|
+
|
|
279
|
+
A node carrying an override the run did not publish belongs to another gesture:
|
|
280
|
+
the run never writes it, never commits it, and reports it to the producer as
|
|
281
|
+
pinned. Dragging a box mid-run is therefore the consumer's ordinary move tool,
|
|
282
|
+
with no gesture contributed by the diagram package.
|
|
283
|
+
|
|
284
|
+
`useLiveLayout` in `@weasel-js/diagram` drives it. `force` relaxes one tick a
|
|
285
|
+
frame off the same force list the one-shot `force` runs, holding a pinned node
|
|
286
|
+
with `fx`/`fy` while its neighbors answer; `layered` and `tree` ease into a
|
|
287
|
+
target computed once. A node or edge appearing or disappearing re-heats the run.
|
|
288
|
+
|
|
289
|
+
`SceneNode.pickable: false` makes a node transparent to the hit-test walk, so a
|
|
290
|
+
press lands on what is behind it. Without it the innermost hit wins and dragging
|
|
291
|
+
a labeled box pulls the label out of the box.
|
|
292
|
+
- b5e2cd9: Solid geometry and image quads now share one batch, so a wall of thumbnails —
|
|
293
|
+
a ground rect under an atlas quad, per cell — draws in one call rather than
|
|
294
|
+
one per command. The two batches used to be exclusive: staging a solid drained
|
|
295
|
+
the image run and staging an image drained the solid one, so a shape that
|
|
296
|
+
batches perfectly in either half alone paid a flush per command. Solid vertices
|
|
297
|
+
carry the UV of a 1x1 white texel, which makes `texture() * a_vertexColor` the
|
|
298
|
+
vertex color exactly, so the merge is pixel-identical rather than close.
|
|
299
|
+
|
|
300
|
+
Measured over a viewport-filling grid of those cells on an M2 Max via ANGLE
|
|
301
|
+
(`tests/perf/atlas-wall.spec.ts`): 600 draw commands 2.83 -> 0.10 ms, 1,650
|
|
302
|
+
11.37 -> 0.20, 5,400 40.50 -> 0.58, 15,000 126.15 -> 1.50. A run still breaks
|
|
303
|
+
on what a run cannot carry — a second bitmap, a different MAG_FILTER, a clip
|
|
304
|
+
depth, a color matrix.
|
|
305
|
+
- 89276ee: `usePoseRun` and `useSimulation` hand their injected clock straight to
|
|
306
|
+
`useVisibleRaf` instead of defaulting it themselves. The gate already falls
|
|
307
|
+
back to `requestAnimationFrame`, so both were defaulting it twice — and the
|
|
308
|
+
copy in `usePoseRun` was a bare `requestAnimationFrame` in kit source, which
|
|
309
|
+
`check:frame-loops` fails the build on. The allowlist is back down to the gate
|
|
310
|
+
itself.
|
|
311
|
+
- 36950d8: `scene.setDependsOn(id, dependsOn)` retargets a node's dependencies as one
|
|
312
|
+
undoable step, so dragging an existing edge's end onto a different node no
|
|
313
|
+
longer means removing the edge and adding another one. Switching a container
|
|
314
|
+
between an id list and `'children'` goes through the same call.
|
|
315
|
+
|
|
316
|
+
Both indices move with it — the reverse dependents index that drives cascade
|
|
317
|
+
delete, and the `'children'` set that drives the ancestor walk — and the
|
|
318
|
+
retargeted node's own memo is dropped alongside its dependents', since its
|
|
319
|
+
derivation now reads different sources. Order is significant, because a
|
|
320
|
+
derivation reads its dependencies positionally; declaring what a node already
|
|
321
|
+
declares records no history entry.
|
|
322
|
+
- 4f8c6b2: Text no longer breaks a batched run. Glyphs, the rules under underlined words,
|
|
323
|
+
and tessellated glyph outlines all stage into the same draw as the solid
|
|
324
|
+
geometry and image quads around them, so a wall of captioned thumbnails is one
|
|
325
|
+
draw where every label used to cost two.
|
|
326
|
+
|
|
327
|
+
The batch shader carries the glyph math behind a paint mode, which packs into
|
|
328
|
+
the texture-slot attribute the vertex already had, so the vertex does not grow
|
|
329
|
+
and a wall of thumbnails costs what it did before. It runs that math on every
|
|
330
|
+
fragment, glyph or not, because `fwidth` in non-uniform control flow is
|
|
331
|
+
undefined and the derivative has to be taken before anything selects on the
|
|
332
|
+
mode — priced at about 1.4% of a fragment that is not a glyph. A synthetic
|
|
333
|
+
oblique now shears on the CPU as the batch places its corners, rather than in a
|
|
334
|
+
vertex shader that read the baseline from a vertex attribute.
|
|
335
|
+
|
|
336
|
+
Three things a run used to break on are gone: a second text color in the same
|
|
337
|
+
paragraph, a decoration whose fill differs from the glyphs it sits under, and
|
|
338
|
+
the difference between a baked MSDF atlas and a runtime canvas bake. What still
|
|
339
|
+
breaks a run is a change of synthetic-bold threshold, which is a uniform — that
|
|
340
|
+
one is a fallback path, since a registered bold face never sets it.
|
|
341
|
+
|
|
342
|
+
**Breaking for anyone importing the text shader sources.** `TEXT_VERT_SRC`,
|
|
343
|
+
`TEXT_FRAG_SRC`, `TEXT_FRAG_R8_SRC`, `TEXT_SDF_UNIFORMS` and
|
|
344
|
+
`TEXT_SDF_ATTRIBUTES` are removed from `@weasel-js/font`: text has no program of
|
|
345
|
+
its own any more. What replaces them is `GLYPH_COVERAGE_GLSL`, the snippet a
|
|
346
|
+
program pastes in to turn an atlas sample into coverage, alongside
|
|
347
|
+
`GLYPH_MODE_MSDF` and `GLYPH_MODE_R8` naming the two channel layouts.
|
|
348
|
+
- 1240956: `kit:text` nodes take a `verticalAlign`, and picking follows it.
|
|
349
|
+
|
|
350
|
+
Centering a glyph in its box meant nudging `pose.y` by hand and re-deriving the
|
|
351
|
+
nudge whenever the font size changed. The painter forwarded the pose's height
|
|
352
|
+
but never an alignment, so the box the renderer aligned within was always
|
|
353
|
+
resolved as `'top'`.
|
|
354
|
+
|
|
355
|
+
`data.verticalAlign` — `'top' | 'center' | 'bottom'`, the same spelling the draw
|
|
356
|
+
command already took — now reaches both halves: the paint command and the
|
|
357
|
+
silhouette `textLineBoxes` builds, so a centered block is grabbable where it
|
|
358
|
+
draws rather than where a top-aligned one would have. A node that names none
|
|
359
|
+
paints exactly where it did before.
|
|
360
|
+
- Updated dependencies [4f8c6b2]
|
|
361
|
+
- @weasel-js/font@1.4.4
|
|
362
|
+
- @weasel-js/text@1.4.4
|
|
363
|
+
- @weasel-js/cursor@1.4.4
|
|
364
|
+
- @weasel-js/geom@1.4.4
|
|
365
|
+
- @weasel-js/gestures@1.4.4
|
|
366
|
+
- @weasel-js/history@1.4.4
|
|
367
|
+
- @weasel-js/modes@1.4.4
|
|
368
|
+
- @weasel-js/paint@1.4.4
|
|
369
|
+
|
|
3
370
|
## 1.4.3
|
|
4
371
|
|
|
5
372
|
### Patch Changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { c as ResizeAnchor, R as ResizePose, B as BoundsConstraint, P as PointSnapBehavior, d as PointSnapFrame, M as ModifierState } from './types-
|
|
2
|
-
import { B as Bounds, P as PoseProjection } from './geometry-
|
|
1
|
+
import { c as ResizeAnchor, R as ResizePose, B as BoundsConstraint, P as PointSnapBehavior, d as PointSnapFrame, M as ModifierState } from './types-ei3UMl9R.js';
|
|
2
|
+
import { B as Bounds, P as PoseProjection } from './geometry-6fCNhAux.js';
|
|
3
3
|
import { D as DebugSink } from './types-BHK2dkMu.js';
|
|
4
|
+
import { P as Path } from './path-JEV2c5If.js';
|
|
4
5
|
|
|
5
6
|
/** Corner resize-handle: world-space center plus the anchor that pins the opposite corner during resize. */
|
|
6
7
|
interface CornerHandle {
|
|
@@ -137,4 +138,18 @@ declare function pointSnapToGrid<TPose extends ResizePose>(args: {
|
|
|
137
138
|
bypassKey?: keyof ModifierState;
|
|
138
139
|
}): PointSnapBehavior<TPose>;
|
|
139
140
|
|
|
140
|
-
|
|
141
|
+
/** True for Path-shaped poses (`{kind: 'polygon' | 'rect'}`). Useful for
|
|
142
|
+
* callers that need to fork between `pathPoseDescriptor` and
|
|
143
|
+
* `RECT_POSE_DESCRIPTOR` without forcing the consumer to wire `geometry`
|
|
144
|
+
* explicitly. */
|
|
145
|
+
declare function isPathLike(p: unknown): p is Path;
|
|
146
|
+
/** Per-call dispatch: if the pose looks like a Path, route to
|
|
147
|
+
* `pathPoseDescriptor`; otherwise treat as a plain rect pose. Avoids forcing
|
|
148
|
+
* demos with Path TPose to wire `geometry={pathPoseDescriptor}` explicitly.
|
|
149
|
+
* `getRotation` surfaces a `pose.rotation` field on non-Path poses so demos
|
|
150
|
+
* using rect-with-rotation shapes (e.g. `RotatedPose`) don't have to wire
|
|
151
|
+
* `geometry={ROTATED_POSE_DESCRIPTOR}` just to get rotated selection chrome
|
|
152
|
+
* and rotation-aware corner hit-tests. */
|
|
153
|
+
declare const AUTO_POSE_DESCRIPTOR: PoseProjection<unknown>;
|
|
154
|
+
|
|
155
|
+
export { AUTO_POSE_DESCRIPTOR as A, CORNER_ANCHORS as C, type UseResizeOptions as U, type CornerAnchor as a, type CornerHandle as b, cornerPoint as c, cornerResizeHandles as d, type CornerEdge as e, fixedCornerOf as f, hitCornerHandle as h, isPathLike as i, pointSnapToGrid as p };
|