@solidrt/core 0.0.52 → 0.0.53
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/AGENTS.md +17 -2
- package/docs/reference/gpu.md +4 -1
- package/package.json +5 -5
- package/src/gpu.ts +18 -2
- package/src/renderer.ts +8 -5
package/AGENTS.md
CHANGED
|
@@ -111,7 +111,7 @@ tsconfig.json - the two load-bearing lines are jsx + jsxImportSource:
|
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
Peer deps @solidjs/signals and @solidjs/universal must match (currently
|
|
114
|
-
2.0.0-rc.
|
|
114
|
+
2.0.0-rc.3); bun resolves them from peerDependencies.
|
|
115
115
|
|
|
116
116
|
## Element model (the parts that are easy to get wrong)
|
|
117
117
|
|
|
@@ -147,6 +147,13 @@ Peer deps @solidjs/signals and @solidjs/universal must match (currently
|
|
|
147
147
|
endpoint props and spans its layout box corner to corner. `points` (a flat
|
|
148
148
|
`[x0, y0, x1, y1, ...]` array, plus `closed`) turns either form into a
|
|
149
149
|
polyline and wins over the endpoints while set.
|
|
150
|
+
- Nesting rule: d-* elements go under anything; laid-out elements only under
|
|
151
|
+
laid-out parents. A detached subtree is entirely detached, and the insert
|
|
152
|
+
throws otherwise (`<view> cannot be a child of <d-view>: ...`). So a
|
|
153
|
+
component that renders any laid-out element is a LAYOUT component and
|
|
154
|
+
cannot be used inside a d-* subtree, and a component meant for d-* trees
|
|
155
|
+
renders d-* only. Say which in the component's doc comment: the types
|
|
156
|
+
cannot tell (every JSX expression is the same `Element`).
|
|
150
157
|
|
|
151
158
|
- Plain vs `d-` variant (the `d-` prefix means "detached" - detached from the
|
|
152
159
|
layout engine, Taffy): a plain element (e.g. `rect`) is `RectProps &
|
|
@@ -267,6 +274,11 @@ Peer deps @solidjs/signals and @solidjs/universal must match (currently
|
|
|
267
274
|
`children()` helper (re-exported from @solidrt/core) and probe the resolved
|
|
268
275
|
memo - never `typeof props.children` on the raw prop.
|
|
269
276
|
|
|
277
|
+
- Keep the simulation out of the renderer: app or game state as plain
|
|
278
|
+
TypeScript with no @solidrt imports, with the JSX reading it and the
|
|
279
|
+
per-frame hook doing one state step plus a handful of property writes.
|
|
280
|
+
That shape runs under bun with no window (tests, audits, replaying a whole
|
|
281
|
+
session in seconds) and it is what keeps per-frame work cheap.
|
|
270
282
|
- Animation is target-shaped first: declare `transition` on the element and
|
|
271
283
|
write targets, and the runtime animates natively with no per-frame JS.
|
|
272
284
|
Reach for per-frame work only for genuinely procedural motion:
|
|
@@ -294,7 +306,10 @@ Peer deps @solidjs/signals and @solidjs/universal must match (currently
|
|
|
294
306
|
|
|
295
307
|
- Device/GPU access via subpath imports: @solidrt/core/camera, /microphone,
|
|
296
308
|
/speech, /gpu. Image flow: `decodeImage(bytes)` ->
|
|
297
|
-
`createTexture(data,w,h)` -> `<texture src={id} />`.
|
|
309
|
+
`createTexture(data,w,h)` -> `<texture src={id} />`. Pixels are
|
|
310
|
+
premultiplied alpha from decode onward (the GPU contract); `decodeImage(bytes,
|
|
311
|
+
{ alpha: "straight" })` keeps the file's color under transparent pixels for
|
|
312
|
+
CPU work, and `encodeImage` converts back to straight for the file.
|
|
298
313
|
|
|
299
314
|
## Minimal app, core primitives only (verified to render)
|
|
300
315
|
|
package/docs/reference/gpu.md
CHANGED
|
@@ -167,7 +167,10 @@ Three facts hold for every texture and target:
|
|
|
167
167
|
a top-left origin.
|
|
168
168
|
- **Color is premultiplied alpha.** A target's RGB is already multiplied by
|
|
169
169
|
its A: write `vec4(rgb * a, a)`. `vec4(rgb, a)` composites as opaque.
|
|
170
|
-
`clearColor` is premultiplied too
|
|
170
|
+
`clearColor` is premultiplied too, and so are uploaded pixels:
|
|
171
|
+
`decodeImage` premultiplies at the codec boundary (image files store
|
|
172
|
+
straight alpha) and `encodeImage` converts back, so pixels inside the app
|
|
173
|
+
are premultiplied everywhere.
|
|
171
174
|
- **Values are non-linear RGBA8** (or `"r8"` for single-channel data), with
|
|
172
175
|
no color-space conversion anywhere. Filtering and blending operate on the
|
|
173
176
|
stored values.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidrt/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.53",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"funding": "https://github.com/sponsors/wellawaretech",
|
|
6
6
|
"author": "Antoine van Wel",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"AGENTS.md"
|
|
30
30
|
],
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@solidrt/flux-types": "0.0.
|
|
32
|
+
"@solidrt/flux-types": "0.0.53"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@solidjs/signals": "2.0.0-rc.
|
|
36
|
-
"@solidjs/universal": "2.0.0-rc.
|
|
37
|
-
"solid-js": "2.0.0-rc.
|
|
35
|
+
"@solidjs/signals": "2.0.0-rc.3",
|
|
36
|
+
"@solidjs/universal": "2.0.0-rc.3",
|
|
37
|
+
"solid-js": "2.0.0-rc.3"
|
|
38
38
|
}
|
|
39
39
|
}
|
package/src/gpu.ts
CHANGED
|
@@ -42,7 +42,10 @@
|
|
|
42
42
|
// multiplied by its A - `vec4(rgb * a, a)`, not `vec4(rgb, a)`, which
|
|
43
43
|
// composites as opaque. That is what Impeller composites and what
|
|
44
44
|
// `<texture blendMode>` blends; `clearColor` is premultiplied too, so the
|
|
45
|
-
// default transparent black needs no thought.
|
|
45
|
+
// default transparent black needs no thought. Uploaded pixels follow the
|
|
46
|
+
// same rule: `decodeImage` premultiplies at the codec boundary (image
|
|
47
|
+
// files store straight alpha) and `encodeImage` undoes it, so pixels
|
|
48
|
+
// inside the app are premultiplied everywhere.
|
|
46
49
|
// - Values are non-linear RGBA8, with no color-space concept. Every texture
|
|
47
50
|
// and target holds 8-bit RGBA UNORM exactly as written; nothing converts to
|
|
48
51
|
// or from linear light. `filter: "linear"` averages and the `blend` modes
|
|
@@ -110,6 +113,7 @@ export {
|
|
|
110
113
|
endBufferWrite,
|
|
111
114
|
resizeTexture,
|
|
112
115
|
setTargetParams,
|
|
116
|
+
setTargetRect,
|
|
113
117
|
setTargetSize,
|
|
114
118
|
setTargetTextures,
|
|
115
119
|
uploadTexture,
|
|
@@ -213,7 +217,9 @@ export { captureSnapshot, readTexture } from "flux:gpu"
|
|
|
213
217
|
* Uploads raw pixels to an immutable GPU texture and returns its id (use it
|
|
214
218
|
* as `<texture src={id} />`). `data` must be exactly `width * height` pixels
|
|
215
219
|
* at the declared format's size (`* 4` bytes for the default "rgba8", `* 1`
|
|
216
|
-
* for "r8"); a mismatch throws.
|
|
220
|
+
* for "r8"); a mismatch throws. RGBA data is uploaded verbatim and composited
|
|
221
|
+
* as premultiplied alpha, like every texture: `decodeImage` and the readback
|
|
222
|
+
* calls already deliver that, and hand-built pixels must too (`rgb * a`). For pixels you intend to mutate and
|
|
217
223
|
* re-upload, use `createMutableTexture` instead. When called inside a
|
|
218
224
|
* reactive scope the texture is freed automatically once that owner is
|
|
219
225
|
* disposed; when called outside one (e.g. after an `await`, where the owner
|
|
@@ -389,6 +395,13 @@ export function createShaderTarget(
|
|
|
389
395
|
* driven later with `setTargetTextures`, same precedence and coverage
|
|
390
396
|
* rules.
|
|
391
397
|
*
|
|
398
|
+
* `into` makes a sub-target: a draw target rendering into the rectangle at
|
|
399
|
+
* `x`/`y` (top-left origin) of draw target `into`'s storage, so N views or
|
|
400
|
+
* N shadow maps share one texture and ONE pass; the id is a draw target to
|
|
401
|
+
* every verb but not a texture (display and sample the parent, with
|
|
402
|
+
* `srcX`/`srcY` on the leaf), and `setTargetRect` moves it. Auto-free works
|
|
403
|
+
* the same way; destroying the parent takes its tiles.
|
|
404
|
+
*
|
|
392
405
|
* The render contract is unchanged: the list is input data, so an ordinary
|
|
393
406
|
* (`render: "auto"`) draw target re-renders exactly when its entries or
|
|
394
407
|
* their inputs change - a static scene costs zero passes, and one render is
|
|
@@ -408,6 +421,9 @@ export function createDrawTarget(
|
|
|
408
421
|
render?: "auto" | "manual"
|
|
409
422
|
loadOp?: "clear" | "load"
|
|
410
423
|
samples?: 1 | 2 | 4 | 8
|
|
424
|
+
into?: gpu.TextureId
|
|
425
|
+
x?: number
|
|
426
|
+
y?: number
|
|
411
427
|
} & CreateOptions &
|
|
412
428
|
SamplerOptions,
|
|
413
429
|
): gpu.TextureId {
|
package/src/renderer.ts
CHANGED
|
@@ -266,6 +266,14 @@ let renderer = createRenderer<ProxyNode>({
|
|
|
266
266
|
pendingDestroy.delete(node.id)
|
|
267
267
|
|
|
268
268
|
if (parent) {
|
|
269
|
+
// console.debug("[srt] insertNode", parent.id, node.id, anchor?.id ?? "")
|
|
270
|
+
|
|
271
|
+
// Native first: the tree refuses a laid-out element under a d-* parent
|
|
272
|
+
// (it throws, naming both tags), and the mirror must not record a child
|
|
273
|
+
// the tree does not have.
|
|
274
|
+
if (anchor) tree.insertNode(parent.id, node.id, anchor.id)
|
|
275
|
+
else tree.insertNode(parent.id, node.id)
|
|
276
|
+
|
|
269
277
|
node.parent = parent
|
|
270
278
|
|
|
271
279
|
if (!anchor) {
|
|
@@ -278,11 +286,6 @@ let renderer = createRenderer<ProxyNode>({
|
|
|
278
286
|
parent.children.splice(index, 0, node)
|
|
279
287
|
}
|
|
280
288
|
}
|
|
281
|
-
|
|
282
|
-
// console.debug("[srt] insertNode", parent.id, node.id, anchor?.id ?? "")
|
|
283
|
-
|
|
284
|
-
if (anchor) tree.insertNode(parent.id, node.id, anchor.id)
|
|
285
|
-
else tree.insertNode(parent.id, node.id)
|
|
286
289
|
}
|
|
287
290
|
},
|
|
288
291
|
|