@solidrt/core 0.0.50 → 0.0.52

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 (42) hide show
  1. package/AGENTS.md +102 -21
  2. package/README.md +1 -1
  3. package/agents/painting.md +61 -0
  4. package/agents/performance.md +216 -0
  5. package/docs/index.md +154 -0
  6. package/docs/reference/detached.md +85 -0
  7. package/docs/reference/drawing.md +95 -0
  8. package/docs/reference/elements.md +56 -0
  9. package/docs/reference/gpu.md +204 -0
  10. package/docs/reference/index.md +50 -0
  11. package/docs/reference/input.md +58 -0
  12. package/docs/reference/layout.md +44 -0
  13. package/docs/reference/shaders.md +46 -0
  14. package/docs/reference/text.md +46 -0
  15. package/docs/reference/transforms.md +35 -0
  16. package/docs/reference/types.md +34 -0
  17. package/examples/README.md +7 -5
  18. package/examples/{sound.tsx → audio.tsx} +1 -1
  19. package/examples/gpu-pipeline.tsx +2 -2
  20. package/examples/gpu-sprites.tsx +102 -0
  21. package/examples/line-points.tsx +145 -0
  22. package/examples/parse-svg.tsx +6 -6
  23. package/examples/responsive-grid.tsx +1 -1
  24. package/examples/scroll.tsx +2 -2
  25. package/examples/snapshot-texture.tsx +72 -0
  26. package/examples/{view-viewbox.tsx → view-design-size.tsx} +33 -15
  27. package/jsx-runtime.d.ts +15 -14
  28. package/package.json +11 -9
  29. package/src/{sound.ts → audio.ts} +68 -15
  30. package/src/color.ts +17 -18
  31. package/src/core.ts +40 -3
  32. package/src/data.ts +99 -0
  33. package/src/gpu.ts +88 -34
  34. package/src/index.ts +9 -3
  35. package/src/logo.tsx +92 -0
  36. package/src/renderer.ts +219 -53
  37. package/src/runtime-modules.d.ts +7 -2
  38. package/src/scroll.ts +51 -15
  39. package/src/svg.ts +1 -1
  40. package/src/text-input.ts +297 -61
  41. package/src/types.d.ts +291 -31
  42. package/src/window.ts +110 -14
@@ -0,0 +1,85 @@
1
+ # Detached elements
2
+
3
+ Every painting element has a detached twin: `d-view`, `d-rect`, `d-oval`,
4
+ `d-line`, `d-path`, `d-text`, `d-texture`. A detached element has no layout
5
+ box. It is not part of the layout at all, and instead owns its geometry in
6
+ paint-space pixels, positioned in the coordinate system of its parent.
7
+
8
+ That is the whole idea, and the reason to reach for one:
9
+
10
+ ```tsx
11
+ let [x, setX] = createSignal(0)
12
+ onFrame((now) => setX(Math.sin(now / 500) * 100))
13
+
14
+ <view width={pct(100)} height={200}>
15
+ <d-rect x={x()} y={20} w={40} h={40} color="tomato" />
16
+ </view>
17
+ ```
18
+
19
+ Moving that rect writes one number to one native property. Nothing reflows,
20
+ because there is nothing in the layout to reflow. The same content as a
21
+ laid-out `<rect>` with `left={x()}` would put the layout engine on the path of
22
+ every frame.
23
+
24
+ **Reach for the detached form first for anything that moves at animation
25
+ frequency**, and for content authored in fixed design units - a chart, a
26
+ diagram, an svg drawing, a particle field. Reach for the layout form when you
27
+ want the element to participate in a flex or grid arrangement, which is most
28
+ static UI.
29
+
30
+ ## What changes
31
+
32
+ A detached element composes exactly the same paint, text and pointer props as
33
+ its layout twin. One thing is swapped: the [layout](/core/reference/layout/)
34
+ props are replaced by geometry props.
35
+
36
+ | | Layout form | Detached form |
37
+ | --- | --- | --- |
38
+ | Position | flex or grid placement, `top`/`left`, margins | `x`, `y` in the parent's coordinates |
39
+ | Size | `width`/`height` and the box it is given | `w`, `h`, defaulting to the inherited box |
40
+ | Costs a reflow | yes | no |
41
+
42
+ `d-view` is the container case: it composes `ViewOwnProps` directly (see
43
+ [elements](/core/reference/elements/)), so it still transforms, clips and
44
+ takes input, but a layout prop on it is dropped with a one-time warning
45
+ rather than silently ignored.
46
+
47
+ `<span>` has no detached form, since an inline run never has a box of its own
48
+ to detach from.
49
+
50
+ ## Geometry
51
+
52
+ Detached geometry is paint-space pixels and never affects layout.
53
+
54
+ {{ decl packages/core/src/types.d.ts PositionProps }}
55
+
56
+ Most primitives add a size, defaulting to the box they inherit from their
57
+ ancestor, so a `d-rect` with only `x`/`y` still has something to draw:
58
+
59
+ {{ decl packages/core/src/types.d.ts GeometryProps }}
60
+
61
+ `d-oval` measures its box rather than a radius:
62
+
63
+ {{ decl packages/core/src/types.d.ts OvalGeometryProps }}
64
+
65
+ For `d-text`, width is the shaping width and height is reported bounds only,
66
+ since a paragraph's height always falls out of the text itself:
67
+
68
+ {{ decl packages/core/src/types.d.ts TextGeometryProps }}
69
+
70
+ `d-path` takes only a position, since its size is whatever its `d` string
71
+ draws. `d-line` has no width and height either: its geometry is its two
72
+ endpoints (or, as a polyline, its `points`), which is what makes it the
73
+ primitive to reach for when the geometry moves. Both report their bounds
74
+ (getBoundingBox, the tree, a capture) as that geometry plus the stroke, not
75
+ the inherited box:
76
+
77
+ {{ decl packages/core/src/types.d.ts LineGeometryProps }}
78
+
79
+ ## The other x and y
80
+
81
+ `x` and `y` also appear on [transform](/core/reference/transforms/) props,
82
+ where they mean a post-layout subtree translation and exist on laid-out views
83
+ too. The two never collide on one element: on a `d-*` primitive `x`/`y` is
84
+ where the geometry is drawn, and on a `view` or `d-view` it is a translation
85
+ applied to the whole subtree. Both are cheap; neither triggers layout.
@@ -0,0 +1,95 @@
1
+ # Drawing
2
+
3
+ The primitives that put pixels on the screen: `rect`, `oval`, `line`, `path`
4
+ and `texture`. They share one paint vocabulary and differ only in the geometry
5
+ they draw.
6
+
7
+ In their layout form they take no geometry props at all. A shape derives its
8
+ geometry from the layout box it sits in, which is why a `rect` with no props
9
+ fills its parent. To place one freely, use the
10
+ [detached form](/core/reference/detached/) instead.
11
+
12
+ ## Paint
13
+
14
+ Fill, stroke and blending, shared by every drawing primitive:
15
+
16
+ {{ decl packages/core/src/types.d.ts PaintProps }}
17
+
18
+ `color` takes a CSS color string or a gradient from `createLinearGradient` /
19
+ `createRadialGradient`. `drawStyle` picks fill, stroke, or both, and the
20
+ stroke props apply to the stroked part.
21
+
22
+ Where the stroke sits relative to the geometry differs by primitive, and it is
23
+ deliberate: a stroked `rect` or `oval` paints *inside* its box like a CSS
24
+ border, so nothing bleeds past the box for a clip to cut, while `line` and
25
+ `path` strokes stay centered on their geometry, where the geometry is the
26
+ stroke rather than a box.
27
+
28
+ ## Dashing
29
+
30
+ A stroke's dash pattern, on `line` and `path`:
31
+
32
+ {{ decl packages/core/src/types.d.ts DashProps }}
33
+
34
+ The pattern is walked along the geometry itself: through a polyline's
35
+ vertices and along a path's curves, restarting at each subpath of a path.
36
+ `dashOffset` slides it - write it every frame for marching ants, or
37
+ transition it for a one-shot slide. A dashed stroke keeps its caps on every
38
+ dash, and a stroke-and-fill path dashes only the stroke.
39
+
40
+ `pathLength` declares what the geometry's length counts as, so the pattern
41
+ can be written in fractions of it: with `pathLength={1}`, `onLength={0.77}
42
+ offLength={1}` draws the first 77%, and transitioning `onLength` from 0 to
43
+ 1 draws the geometry on (the SVG line-drawing trick, without having to know
44
+ the length).
45
+
46
+ ## rect
47
+
48
+ {{ decl packages/core/src/types.d.ts RectProps }}
49
+
50
+ ## oval
51
+
52
+ {{ decl packages/core/src/types.d.ts OvalProps }}
53
+
54
+ ## line
55
+
56
+ {{ decl packages/core/src/types.d.ts LineProps }}
57
+
58
+ A laid-out `<line>` without `points` draws its box's top-left-to-bottom-right
59
+ diagonal, so in practice it is a rule: give it a thin box. Endpoints are a
60
+ detached-only concept, so arbitrary angles and connectors want `d-line`.
61
+ `points` makes either form a polyline - a flat `[x0, y0, x1, y1, ...]` array
62
+ (or a `Float32Array`), optionally `closed` - the numeric middle ground between
63
+ a segment and a path: animate it by writing a new array, nothing is parsed.
64
+ Curves want a path.
65
+
66
+ ## path
67
+
68
+ {{ decl packages/core/src/types.d.ts PathProps }}
69
+
70
+ `d` is an SVG path string. Reach for `line` instead when the geometry is
71
+ numbers that animate (endpoints, or a polyline's `points`): a path animates
72
+ by rebuilding its `d` string, where a line moves one number or one array.
73
+ A path dashes like a line (see Dashing above), the pattern restarting at
74
+ each subpath; the dash props are paint-only writes, the `d` is not re-parsed.
75
+
76
+ ## texture
77
+
78
+ A GPU texture: a decoded image, a camera frame, a video frame, or a shader
79
+ render target. `src` is a texture id, never a URL, which keeps one currency
80
+ for every pixel source in the engine.
81
+
82
+ {{ decl packages/core/src/types.d.ts TextureProps }}
83
+
84
+ ## Logo
85
+
86
+ The SolidRT brand mark, the same seven-segment puzzle the scaffold's welcome
87
+ screen and the launcher draw, as a component: a square `view` of `size`
88
+ pixels with the segments as gradient-filled `d-path`s.
89
+
90
+ {{ decl packages/core/src/logo.tsx LogoProps }}
91
+
92
+ The default is static and requests no frames; `"once"` and `"loop"` drive a
93
+ staggered per-segment fade through `onFrame`, so the animated forms hold a
94
+ frame request only while they run (`"once"` releases it when the last
95
+ segment is in).
@@ -0,0 +1,56 @@
1
+ # Elements
2
+
3
+ The two structural elements. Neither one paints: `window` is the root, `view`
4
+ is a box that lays out, clips, transforms and receives input. Everything
5
+ visible comes from the [drawing](/core/reference/drawing/) and
6
+ [text](/core/reference/text/) primitives inside them.
7
+
8
+ ## window
9
+
10
+ One per app, the root of the tree. It composes
11
+ [layout](/core/reference/layout/) props, so the window is itself the outermost
12
+ flex container, and [pointer](/core/reference/input/) props, which is where
13
+ app-global key handling lives: key events always end their walk at the window
14
+ root.
15
+
16
+ {{ decl packages/core/src/types.d.ts WindowProps }}
17
+
18
+ The `shader` prop runs the finished frame through a GPU program as the last
19
+ step before the screen; see [shaders](/core/reference/shaders/).
20
+
21
+ ## view
22
+
23
+ A `view` never paints. There is no `backgroundColor`: you put a `rect` behind
24
+ the content, and a shape with no geometry of its own fills the layout box it
25
+ sits in.
26
+
27
+ ```tsx
28
+ <view padding={16} alignItems="center">
29
+ <rect color="#1b2440" radius={12} />
30
+ <text color="white">Boxed</text>
31
+ </view>
32
+ ```
33
+
34
+ Its props split in two. `ViewOwnProps` is everything a view offers besides
35
+ layout, and it is what the detached `d-view` composes on its own:
36
+
37
+ {{ decl packages/core/src/types.d.ts ViewOwnProps }}
38
+
39
+ The laid-out `view` is that plus the layout props:
40
+
41
+ {{ decl packages/core/src/types.d.ts ViewProps }}
42
+
43
+ Three of those props are worth knowing before you need them:
44
+
45
+ - `designSize` fits a design-space coordinate system into the element's box,
46
+ scaled uniformly and centered. Everything under the view - layout, paint,
47
+ input - happens in design units, and the view itself sizes like a
48
+ replaced element whose intrinsic size is the design size. It is the
49
+ natural wrapper for `parseSvg` output, any `d-*` subtree authored in
50
+ fixed units, or a whole laid-out panel that should scale rather than
51
+ reflow.
52
+ - `repaintBoundary` retains the subtree's display list, and in its
53
+ `"snapshot"` forms its rasterized pixels too. It is the lever for putting
54
+ heavy static content next to content that changes every frame.
55
+ - `clipRadius` rounds the clip, and only does anything when `overflow` is
56
+ non-visible.
@@ -0,0 +1,204 @@
1
+ # GPU
2
+
3
+ `@solidrt/core/gpu` is the programmable half of rendering: textures you
4
+ upload, shader passes that render into textures, and pipelines that draw
5
+ your own geometry into them. Everything it produces is a texture id, and a
6
+ texture id goes anywhere a texture goes: `<texture src={id} />` to display
7
+ it, a `textures` binding to sample it from another pass, `readTexture` to
8
+ bake it.
9
+
10
+ The imperative primitives (`uploadTexture`, `setTargetParams`, `addDraw`,
11
+ `destroyTexture`, ...) are the `flux:gpu` module and are documented in the
12
+ [runtime reference](/runtime/gui/gpu/). This page is the reactive layer
13
+ over them and the contracts that hold across both.
14
+
15
+ ## The model
16
+
17
+ A target is retained, not redrawn. Creating one renders it once; after that
18
+ it re-renders exactly when something it depends on changes - a param, a
19
+ bound texture, a buffer it draws from, its size - and never otherwise. A
20
+ static shader costs zero passes per frame.
21
+
22
+ Sampler bindings are live dependencies. A target bound as another's
23
+ `textures` input re-renders its consumer whenever it re-renders itself, in
24
+ topological order, so a chain (a plasma pass feeding a mesh pipeline) is
25
+ driven by writing only the first target's uniforms. A cycle throws.
26
+
27
+ Targets whose pass is state rather than a function of its inputs
28
+ (accumulation, feedback, simulation) opt out with `render: "manual"`: the
29
+ runtime never renders them, only `renderTarget(id)` does, in call order,
30
+ normally from `onFrame`.
31
+
32
+ ## Three layers
33
+
34
+ - **Fused.** `createShaderTexture` compiles a fragment source and renders it
35
+ fullscreen; `createPipelineTexture` does the same over your own vertex
36
+ buffer. One call, one texture, program and target sharing a lifetime. The
37
+ shader-toy shape.
38
+ - **Raw.** `compileShader`, `linkProgram`, `createRenderPipeline`, then
39
+ `createShaderTarget` per target. A pipeline (program plus draw state:
40
+ attribute layout, topology, blend, cull, depth) backs any number of targets
41
+ and compiles nothing per target. Reach for it when programs are shared or
42
+ lifetimes differ.
43
+ - **Draw list.** `createDrawTarget` renders many entries in one pass, each
44
+ entry its own pipeline, buffer, params and textures, added and removed with
45
+ `addDraw` / `removeDraw` and sorted with `setDrawOrder`. A scene, in one
46
+ texture.
47
+
48
+ `@solidrt/3d` builds its scene graph on the third layer; nothing there is
49
+ hidden from this one.
50
+
51
+ ## Creating
52
+
53
+ Every `create*` helper frees its resource when the reactive owner that
54
+ created it is disposed. Created outside a reactive scope (after an `await`,
55
+ in an event handler with no owner) nothing is registered and the matching
56
+ `destroy*` is yours to call; `{ autoFree: false }` opts out of the auto-free
57
+ inside a scope for resources rebuilt by hand. `label` names the resource in
58
+ the dev tooling's GPU inventory and in engine log messages.
59
+
60
+ {{ decl packages/core/src/gpu.ts createTexture }}
61
+
62
+ {{ decl packages/core/src/gpu.ts createMutableTexture }}
63
+
64
+ {{ decl packages/core/src/gpu.ts createShaderTexture }}
65
+
66
+ {{ decl packages/core/src/gpu.ts createPipelineTexture }}
67
+
68
+ {{ decl packages/core/src/gpu.ts createShaderTarget }}
69
+
70
+ {{ decl packages/core/src/gpu.ts createDrawTarget }}
71
+
72
+ {{ decl packages/core/src/gpu.ts createShaderTextureMemo }}
73
+
74
+ {{ decl packages/core/src/gpu.ts ShaderSpec }}
75
+
76
+ ## Buffers
77
+
78
+ {{ decl packages/core/src/gpu.ts createBuffer }}
79
+
80
+ {{ decl packages/core/src/gpu.ts beginBufferWrite }}
81
+
82
+ {{ decl packages/core/src/gpu.ts writeBuffer }}
83
+
84
+ A buffer's size is fixed at creation, an entry's buffers are not: `setDraw`
85
+ (single-draw targets) and `setDrawBuffers` (draw-list entries) re-point a
86
+ role the entry already fills - `buffer`, `indexBuffer` + `indexFormat`,
87
+ `instanceBuffer` - at another buffer. That is how a population grows past
88
+ its reservation: create a larger buffer, write it, swap, destroy the old.
89
+ The swap is replace-only (roles are pipeline layout state) and keeps the
90
+ entry's draw range, rechecked against the new sizes.
91
+
92
+ ## Uniforms
93
+
94
+ Uniforms are driven by name. Declaratively, `<texture src={id}
95
+ params={{ uTime: t() }} />` writes the target's params paced to the next real
96
+ repaint, which is the preferred form; `setTargetParams` and `setDrawParams`
97
+ are the imperative forms for targets no element holds. A number drives a
98
+ scalar, a flat number array drives the declared type (2, 3, 4 for `vec2`,
99
+ `vec3`, `vec4`, 16 column-major for `mat4`, element size times length for
100
+ arrays). `textures` binds `sampler2D` uniforms to texture ids the same way.
101
+
102
+ Every write is validated at the call site against the linked program:
103
+
104
+ - a name the program never declares throws, listing the active uniforms;
105
+ - a value whose length does not fit the declared type throws;
106
+ - a `sampler2D` named in `params` (or a non-sampler named in `textures`)
107
+ throws;
108
+ - a name the source declares but the compiler optimized out is accepted
109
+ with a warning and skipped, so one param object can drive several shader
110
+ variants that do not all read every uniform.
111
+
112
+ On a draw target, target-level `params` and `textures` are the shared set
113
+ every entry reads (a camera's view-projection written once per move), applied
114
+ before each entry's own, and a shared name only some entries declare applies
115
+ where declared.
116
+
117
+ The fused preamble declares exactly what the runtime provides: `#version
118
+ 300 es`, precision, `vUV` (fragment path), `fragColor`, and `iResolution`,
119
+ filled with the target size in physical pixels. Anything app-driven - a time
120
+ uniform - is the source's own declaration, driven like any other uniform, so
121
+ forgetting to drive it is a compile error rather than a value stuck at zero.
122
+ A source starting with its own `#version` line gets no preamble and compiles
123
+ as written.
124
+
125
+ ## Sampling
126
+
127
+ `filter` (`"linear"` default, `"nearest"`), `wrap` (`"clamp"` default,
128
+ `"repeat"`) and `mipmap` (`false` default) are declared at creation and are
129
+ a property of the texture id: `<texture>` display and shader sampling follow
130
+ the same state, so a nearest texture upscales with hard pixels everywhere.
131
+ Changing any of them means a new id.
132
+
133
+ Without a mip chain, shader sampling of a minified texture skips texels and
134
+ aliases (3d surfaces at distance, a target sampled at a fraction of its
135
+ size). `mipmap: true` keeps the chain on the id and the runtime rebuilds it
136
+ after every upload (data textures) and every render (targets) - there is
137
+ nothing to schedule. Shader sampling then minifies through it (trilinear
138
+ for `"linear"`, per-level nearest for `"nearest"`). The `<texture>` display
139
+ draw samples the full-size level only, so a supersampled target shown
140
+ through `<texture>` should stay at 2x. Rebuilding is one GPU pass per
141
+ upload or render; a per-frame texture pays it per frame.
142
+
143
+ One binding can deviate: a `textures` value may be `{ id, filter?, wrap? }`
144
+ instead of a bare id, sampling that texture with a different filter or
145
+ wrap in this binding only - blur a `"nearest"` atlas linearly, tile a
146
+ clamped target in one consumer. The texture's own state stays what
147
+ `<texture>` paints and what every other binding uses. `mipmap` is not
148
+ overridable: the chain either exists on the id or it does not.
149
+
150
+ ## Blending
151
+
152
+ Combining passes is a render-tree job: stack `<texture>` elements and set
153
+ `blendMode` on them. Within one pipeline draw, `blend` on the pipeline
154
+ decides how overlapping geometry combines: `"add"` and `"multiply"` are
155
+ order-independent (glows, shadows); `"alpha"` composites over in draw-list
156
+ order with premultiplied output, normally after the opaques with
157
+ `depthWrite: false`, and nothing sorts for you (`setDrawOrder` does, or a
158
+ scene layer above). Anything else overwrites.
159
+
160
+ ## The pixel contract
161
+
162
+ Three facts hold for every texture and target:
163
+
164
+ - **Clip space is y-down.** `gl_Position` y = -1 is the top of the target.
165
+ A vertex stage carrying camera-up geometry negates y or folds the flip into
166
+ its projection. The fragment path absorbs the flip, so `vUV` is 0..1 with
167
+ a top-left origin.
168
+ - **Color is premultiplied alpha.** A target's RGB is already multiplied by
169
+ its A: write `vec4(rgb * a, a)`. `vec4(rgb, a)` composites as opaque.
170
+ `clearColor` is premultiplied too.
171
+ - **Values are non-linear RGBA8** (or `"r8"` for single-channel data), with
172
+ no color-space conversion anywhere. Filtering and blending operate on the
173
+ stored values.
174
+
175
+ ## UI as a texture
176
+
177
+ `snapshotTexture(ref)` (from `@solidrt/core`) is the texture id behind a
178
+ `repaintBoundary="snapshot"` view: the subtree's rasterized pixels, usable
179
+ wherever a texture id is - a `<texture>`, a shader or draw target binding,
180
+ a 3d material. The id is allocated on first call and stable for the node's
181
+ lifetime; the runtime re-points it after every re-rasterization, which
182
+ happens only when the subtree changes, so a static panel sampled by an
183
+ animated consumer costs no repaint. Premultiplied, top-left origin, cropped
184
+ to the layout box. Empty until the boundary's first paint. The boundary owns
185
+ it: `destroyTexture` on it throws, and unmounting the boundary releases it
186
+ on the deferred-destroy path (a consumer still sampling it keeps the last
187
+ pixels). A boundary showing its own texture is not a feedback loop: its
188
+ rasterization is the change, so it does not re-invalidate itself.
189
+
190
+ ## Readback
191
+
192
+ `captureSnapshot` renders a render-tree node to pixels and `readTexture`
193
+ reads any texture back; both resolve `{ width, height, data }`. This is the
194
+ one-shot bake path (a glyph atlas, a processed image), paid for with a
195
+ readback stall and a paint pass of latency per call. Never per frame; to
196
+ feed live content into a shader, bind a texture that updates in place
197
+ instead - for a UI subtree, `snapshotTexture`.
198
+
199
+ ## Limits
200
+
201
+ `limits` holds the device ceilings queried at startup: maximum texture and
202
+ target size, sampler inputs per pass, vertex attributes per pipeline. Creates
203
+ and binds validate against them and throw naming the limit; read them to
204
+ size within the device instead.
@@ -0,0 +1,50 @@
1
+ # Reference
2
+
3
+ Core's API is its types. `@solidrt/core` ships `types.d.ts` and
4
+ `jsx-runtime.d.ts` as sources, with a doc comment on every prop that deviates
5
+ from the CSS or DOM meaning you already expect, so these pages show those
6
+ declarations directly rather than paraphrasing them.
7
+
8
+ They are grouped by subject, not by element. Most props live on several
9
+ elements at once (every element takes pointer handlers, every drawing
10
+ primitive takes paint props), so a page per element would print the same
11
+ interface a dozen times and still not say where a prop comes from.
12
+
13
+ - [Elements](/core/reference/elements/) - `window` and `view`, the structural
14
+ vocabulary
15
+ - [Drawing](/core/reference/drawing/) - `rect`, `oval`, `line`, `path`,
16
+ `texture`, and the paint props they share
17
+ - [Text](/core/reference/text/) - `text` and `span`
18
+ - [Detached elements](/core/reference/detached/) - the `d-*` forms and their
19
+ paint-space geometry
20
+ - [Layout](/core/reference/layout/) - flexbox, the grid subset, and the box
21
+ props
22
+ - [Transforms](/core/reference/transforms/) - post-layout transform, opacity,
23
+ and scroll offsets
24
+ - [Input](/core/reference/input/) - handlers and the event objects they receive
25
+ - [Shaders](/core/reference/shaders/) - the `shader` prop on `window` and
26
+ `view`
27
+ - [GPU](/core/reference/gpu/) - textures, shader targets, pipelines and the
28
+ draw list from `@solidrt/core/gpu`
29
+ - [Types](/core/reference/types/) - the shared aliases
30
+
31
+ ## The element vocabulary
32
+
33
+ Every JSX intrinsic and the prop interfaces it composes. `ref` is available on
34
+ all of them and is left out here.
35
+
36
+ {{ intrinsics packages/core/jsx-runtime.d.ts }}
37
+
38
+ Read a row as the sum of its parts: `<rect>` takes paint props, pointer props
39
+ and layout props, while `<d-rect>` swaps the layout props for detached
40
+ geometry. The pages above cover the interfaces in that table.
41
+
42
+ ## Clearing a prop
43
+
44
+ Writing `undefined` (or `null`) to a prop resets it to its default - the
45
+ value it had before anything was set, per element kind. So the reactive
46
+ pattern `scale={style()?.scale}` is safe: when the binding clears, the
47
+ element returns to its unset state instead of erroring. On a `span`,
48
+ clearing a prop returns the run to inheriting from its paragraph. Content
49
+ props are the exception: `text` on a span and `d` on a path require a value.
50
+ A wrong-typed value is an error either way.
@@ -0,0 +1,58 @@
1
+ # Input
2
+
3
+ Pointer, wheel, key and text events are props on any element. There is no
4
+ `addEventListener` and no event registry: a handler prop is the subscription.
5
+
6
+ Events travel from the hit leaf up to the root, and `stopPropagation()` ends
7
+ the walk.
8
+
9
+ ## Handlers
10
+
11
+ {{ decl packages/core/src/types.d.ts PointerProps }}
12
+
13
+ `pointerEvents="none"` takes an element out of hit testing, and the walk skips
14
+ it as an ancestor too, so the `parentX`/`parentY` of an event stay in the frame
15
+ you would expect.
16
+
17
+ Focus is explicit: `setFocus(node)` moves it, `onFocus`/`onBlur` report it,
18
+ and `focusable` only marks an element as a candidate for `getFocusables()`,
19
+ so a focus-navigation scheme (a component set's, or your own) can enumerate
20
+ targets without the runtime imposing one.
21
+
22
+ ## Pointer events
23
+
24
+ Coordinates are logical points, so a handler reads the same numbers on a
25
+ high-density phone screen as on a desktop monitor. Three frames are reported,
26
+ which is what makes drag idioms short:
27
+
28
+ {{ decl packages/core/src/types.d.ts PointerEvent }}
29
+
30
+ The drag idiom is `x = parentX - grab offset`, taking the grab offset from
31
+ `localX`/`localY` at pointer down.
32
+
33
+ {{ decl packages/core/src/types.d.ts WheelEvent }}
34
+
35
+ ## Key events
36
+
37
+ Key events use the W3C UI Events vocabulary: `key` is the logical,
38
+ layout-dependent value (`"a"`, `"!"`, `"Enter"`, `"ArrowLeft"`), and `code` is
39
+ the physical key position (`"KeyA"`, `"Digit1"`).
40
+
41
+ {{ decl packages/core/src/types.d.ts KeyEvent }}
42
+
43
+ Routing differs from pointer events in where the walk starts: keydown and
44
+ keyup dispatch along the focused node's ancestor chain and always end at the
45
+ window root, and with nothing focused they go to the window root alone.
46
+ `<window onKeyDown>` is therefore the app-global shortcut point.
47
+
48
+ ## Text entry
49
+
50
+ Printable characters do not arrive as key events. Text entry goes to the
51
+ focused node's `onTextInput`:
52
+
53
+ {{ decl packages/core/src/types.d.ts TextEvent }}
54
+
55
+ Focusing a field never raises the on-screen keyboard by itself. A tap on the
56
+ field does, or an explicit `startTextInput()`, and never while a physical
57
+ keyboard is attached. `textInputHints` on the node is read when a session
58
+ starts.
@@ -0,0 +1,44 @@
1
+ # Layout
2
+
3
+ Layout is flexbox plus a line-based subset of CSS grid, over the whole element
4
+ tree. Prop names match CSS, so `flexDirection`, `alignItems`,
5
+ `justifyContent`, `gap`, `padding` and `width` mean what you expect.
6
+
7
+ These props exist on `window`, `view`, and the layout form of every drawing
8
+ and text primitive. They do not exist on the
9
+ [detached](/core/reference/detached/) forms, which own their geometry instead.
10
+
11
+ ## Units
12
+
13
+ A bare number is pixels. A percentage is `pct(50)`, a branded value rather
14
+ than a parsed string, though the `"50%"` string form is accepted so pasted CSS
15
+ keeps working.
16
+
17
+ ```tsx
18
+ <view flexDirection="row" gap={8} padding={16}>
19
+ <view width={pct(50)} />
20
+ </view>
21
+ ```
22
+
23
+ {{ decl packages/core/src/types.d.ts Dimension }}
24
+
25
+ {{ decl packages/core/src/types.d.ts LengthPercentage }}
26
+
27
+ ## The box
28
+
29
+ {{ decl packages/core/src/types.d.ts LayoutProps }}
30
+
31
+ Two divergences from CSS are worth reading twice. `position` has `relative`
32
+ and `absolute` only, and an absolute element does not itself become a
33
+ containing block: it resolves against the nearest ancestor with
34
+ `position="relative"`. And `float` / `clear` are not page layout; they apply
35
+ to an element child of a `<text>`, where it becomes an inline atom the lines
36
+ wrap around.
37
+
38
+ ## Flexbox
39
+
40
+ {{ decl packages/core/src/types.d.ts FlexboxProps }}
41
+
42
+ ## Grid
43
+
44
+ {{ decl packages/core/src/types.d.ts GridProps }}
@@ -0,0 +1,46 @@
1
+ # Shaders
2
+
3
+ Two elements take a `shader` prop: `window` runs a program over the finished
4
+ frame, and `view` runs one over its own rasterized subtree. Both are
5
+ declarative - the pass exists while the prop is declared and the resources go
6
+ away when it is removed.
7
+
8
+ Everything about the program itself (compiling, linking, lifetime) belongs to
9
+ the raw shading layer: `compileShader` and `linkProgram` from
10
+ `@solidrt/core/gpu`.
11
+
12
+ ## The shared contract
13
+
14
+ Both passes bind their input as `uniform sampler2D uSource` with a top-left
15
+ origin, like every sampled texture in the engine, and fill `iResolution` by
16
+ name with the pass size in physical pixels. Both fill `params` uniforms by
17
+ name, paced to the next real repaint: a number drives a scalar, and a flat
18
+ number array drives the declared GLSL type (2, 3 or 4 for `vec2`, `vec3`,
19
+ `vec4`, and 16 column-major for `mat4`).
20
+
21
+ ## Window
22
+
23
+ {{ decl packages/core/src/types.d.ts WindowShaderProps }}
24
+
25
+ The window pass draws attributeless triangles with `vertexCount` vertices
26
+ fetched via `gl_VertexID`, defaulting to a single covering triangle.
27
+
28
+ ## View
29
+
30
+ A boundary shader requires a snapshot boundary (`repaintBoundary="snapshot"`
31
+ or `"snapshot-no-aa"`). The cost is snapshot semantics, and it is kept
32
+ explicit: declared without one, the shader is ignored with a warning.
33
+
34
+ {{ decl packages/core/src/types.d.ts ViewShaderProps }}
35
+
36
+ The pass is split from content invalidation, so animating `params` over a
37
+ static subtree re-runs only the pass against the cached snapshot and never
38
+ re-rasterizes it.
39
+
40
+ The effect samples the subtree's own pixels and nothing else. Grading,
41
+ warping and dissolving a panel work; anything that needs what is *behind* the
42
+ panel does not. Hit testing stays on layout geometry, so a distortion moves
43
+ pixels, not hit targets.
44
+
45
+ `outset` grows the rasterized canvas by a transparent margin on every side,
46
+ for effects that write past the edge such as a glow or a drop shadow.