@solidrt/core 0.0.51 → 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.
package/AGENTS.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @solidrt/core - agent notes
2
2
 
3
- Dense, self-contained facts for writing a SolidRT app.
4
- Full docs live in docs/ (and the website). When this conflicts with prose docs,
5
- trust this file and the types in src/types.d.ts and jsx-runtime.d.ts.
3
+ Dense, self-contained facts for writing a SolidRT app. The prose lives in
4
+ docs/ (also the website); when this conflicts with it, trust this file and
5
+ the types in src/types.d.ts and jsx-runtime.d.ts.
6
6
 
7
7
  SolidRT is a custom SolidJS renderer: it paints through a Rust runtime, not the
8
8
  DOM. There is no HTML, no CSS cascade, no `className`.
@@ -35,12 +35,19 @@ hardcode desktop pixels.
35
35
 
36
36
  Exception - fixed-aspect content. For content with fixed internal geometry
37
37
  (diagrams, slides, dashboards, games, emulators), do not branch on window size
38
- at all: author everything in one design space and let `viewBox` fit it.
39
- `<view flex={1} viewBox={[1280, 800]}>` uniformly scales and centers the
38
+ at all: author everything in one design space and let `designSize` fit it.
39
+ `<view flex={1} designSize={[1280, 800]}>` uniformly scales and centers the
40
40
  children (letterboxed), pointer events on them arrive in design coordinates,
41
- and the same code runs unchanged from a desktop window to a phone. Reach for
42
- `windowSizeClass` branching only when the layout genuinely reflows across form
43
- factors.
41
+ and the same code runs unchanged from a desktop window to a phone. Laid-out
42
+ children (flex, percentages, text wrap) resolve against the design size too,
43
+ so a whole panel scales into a smaller box without reflowing; the view itself
44
+ sizes like a replaced element whose intrinsic size is the design size. One
45
+ trap from flexbox, not from designSize: in a flex row a width-only design-size view
46
+ is stretched to the line's height under the default alignment, so give the
47
+ view `alignSelf="flex-start"` (or the row a non-stretch `alignItems`) to get
48
+ the design aspect - `aspectRatio` does not override stretch. Reach for
49
+ `windowSizeClass` branching only when the layout genuinely reflows across
50
+ form factors.
44
51
 
45
52
  `env` and `capabilities` (both exported from `@solidrt/core`) are the two
46
53
  objects that expose this. They are plain objects with REACTIVE GETTERS, not
@@ -73,7 +80,7 @@ you need the raw fact (e.g. `env.displayScale` for asset sizing below).
73
80
  Because the drawn size is fluid and the display DPI varies, asset format is a
74
81
  real design decision, not an afterthought:
75
82
 
76
- - Prefer VECTORS (`parseSvg` draws mapped to `<d-path>` in a `viewBox` view)
83
+ - Prefer VECTORS (`parseSvg` draws mapped to `<d-path>` in a `designSize` view)
77
84
  whenever the render size is fluid or DPI varies - they stay crisp at any
78
85
  size x `displayScale()`.
79
86
  - RASTER (`<texture>` / `createImage`) needs source resolution >= displayed size
@@ -88,8 +95,9 @@ bun add @solidrt/core # the renderer
88
95
  bun add -d @solidrt/cli # the `srt` tool (see its AGENTS.md)
89
96
  ```
90
97
 
91
- `@solidrt/components` is a separate, optional package of higher-level components
92
- (see its own AGENTS.md); core primitives alone are enough to build a full app.
98
+ Core primitives alone are enough to build a full app. The optional extensions
99
+ (each with its own AGENTS.md) build on it: `@solidrt/components` (themed
100
+ widgets), `@solidrt/2d` (2D graphics and games), `@solidrt/3d` (scene graph).
93
101
 
94
102
  tsconfig.json - the two load-bearing lines are jsx + jsxImportSource:
95
103
 
@@ -103,13 +111,23 @@ tsconfig.json - the two load-bearing lines are jsx + jsxImportSource:
103
111
  ```
104
112
 
105
113
  Peer deps @solidjs/signals and @solidjs/universal must match (currently
106
- 2.0.0-rc.0); bun resolves them from peerDependencies.
114
+ 2.0.0-rc.1); bun resolves them from peerDependencies.
107
115
 
108
116
  ## Element model (the parts that are easy to get wrong)
109
117
 
110
118
  - `render(() => <App />)`. The returned root MUST be a `<window>` or it throws.
111
119
  Call render once, at the top level.
112
120
 
121
+ - Errors never halt the app. One thrown while computing an element's props or
122
+ a child expression is contained at that element: it keeps its last good
123
+ value, one `Contained error` log line names the node and the .tsx line,
124
+ and it recovers when the expression computes again. Anything unclaimed
125
+ beyond that (a throwing `createEffect`, an error while mounting) reaches
126
+ render()'s root boundary, which replaces the app's window with an error
127
+ window (message, stack, a Reset button that retries the failed
128
+ computations) and logs `Uncaught error`. `<Errored>` gives a subtree its
129
+ own in-place fallback.
130
+
113
131
  - Two kinds of element:
114
132
  - Containers - `<window>`, `<view>`. Do layout + transform + pointer events.
115
133
  THEY DO NOT PAINT. A `<view>` has no background/fill prop.
@@ -122,11 +140,13 @@ Peer deps @solidjs/signals and @solidjs/universal must match (currently
122
140
  Outlines: `drawStyle="stroke"` (or "stroke-and-fill") plus `strokeWidth`.
123
141
  Corner radius on draw primitives: `radius` (number or [tl, tr, br, bl]).
124
142
 
125
- - Registered JSX intrinsics: `window`, `view`, `text`, `rect`, `oval`, `line`,
126
- `path`, `texture`, `audio`, plus the `d-` variants `d-view`, `d-rect`,
143
+ - Registered JSX intrinsics: `window`, `view`, `text`, `span`, `rect`, `oval`,
144
+ `line`, `path`, `texture`, `audio`, plus the `d-` variants `d-view`, `d-rect`,
127
145
  `d-oval`, `d-line`, `d-path`, `d-texture`, `d-text`. Line endpoints
128
146
  (`x1`/`y1`/`x2`/`y2`) exist only on `d-line`; a laid-out `<line>` has no
129
- endpoint props and spans its layout box corner to corner.
147
+ endpoint props and spans its layout box corner to corner. `points` (a flat
148
+ `[x0, y0, x1, y1, ...]` array, plus `closed`) turns either form into a
149
+ polyline and wins over the endpoints while set.
130
150
 
131
151
  - Plain vs `d-` variant (the `d-` prefix means "detached" - detached from the
132
152
  layout engine, Taffy): a plain element (e.g. `rect`) is `RectProps &
@@ -165,6 +185,10 @@ Peer deps @solidjs/signals and @solidjs/universal must match (currently
165
185
  `position:absolute` at `left:0,top:0`, or just let normal flow place it) and
166
186
  then translate it with `x`/`y`.
167
187
 
188
+ - Text `lineHeight` is a MULTIPLIER of fontSize (1.3-1.6 is typical), not
189
+ pixels. A CSS-reflex value like 22 makes each line box 22x the font size:
190
+ the text becomes blank space and the parent balloons.
191
+
168
192
  - JSX text children collapse whitespace (ordinary JSX semantics): runs of
169
193
  spaces become one, so space-padding a mono label collapses silently. An
170
194
  expression container preserves it - `<d-text>{"one two"}</d-text>` - and
@@ -218,9 +242,55 @@ Peer deps @solidjs/signals and @solidjs/universal must match (currently
218
242
  TRACKED compute that reads signals and returns a value, then an UNTRACKED
219
243
  effect that receives it - `createEffect(() => count(), (c) => ...)`. The 1.x
220
244
  single-callback form `createEffect(() => { ...count()... })` does NOT track
221
- here. Per-frame work: `onFrame((tick, frame) => {})` (returns a cleanup;
222
- auto-cleaned inside a reactive scope) or standard `requestAnimationFrame`.
223
- Also onResize, onLayout, onWindowFocus, onWindowBlur.
245
+ here.
246
+ Reading a signal/prop/store at the top level of a component body (not
247
+ inside JSX, a `createMemo`, or an effect's compute phase) reads it
248
+ untracked: it silently freezes at the initial value.
249
+ Writing a signal or store from inside an owned scope (a component body, a
250
+ `createMemo`, an effect's compute phase) throws
251
+ `REACTIVE_WRITE_IN_OWNED_SCOPE` in dev; a loader called in the component
252
+ body that sets state is the classic React / Solid 1.x reflex that hits
253
+ this. Move the write into an event handler, an effect's apply phase,
254
+ `onSettled`, or an `untrack` block; opt in narrowly with
255
+ `createSignal(v, { ownedWrite: true })` for a signal that genuinely is
256
+ internal state.
257
+ Signal writes flush on a microtask: a handler that sets a signal and
258
+ immediately reads it back gets the OLD value. Read it in an effect, or
259
+ call `flush()` (from @solidjs/signals) to force it through.
260
+
261
+ - An element-valued prop (children, a content/icon slot) compiles to a getter
262
+ that builds a fresh native subtree on EVERY read, and a subtree that is
263
+ never inserted is never freed - native nodes are not garbage collected, so
264
+ what is only wasted work in DOM Solid is a permanent memory leak here. Read
265
+ such props exactly once, at the place they are mounted. To inspect
266
+ children (a typeof probe, counting), resolve them first with the
267
+ `children()` helper (re-exported from @solidrt/core) and probe the resolved
268
+ memo - never `typeof props.children` on the raw prop.
269
+
270
+ - Animation is target-shaped first: declare `transition` on the element and
271
+ write targets, and the runtime animates natively with no per-frame JS.
272
+ Reach for per-frame work only for genuinely procedural motion:
273
+ `onFrame((tick, frame) => {})` is the native hook (runtime-paced, returns a
274
+ cleanup, auto-cleaned inside a reactive scope); `requestAnimationFrame`
275
+ exists as a web-standard one-shot but is not the preferred driver. A JS
276
+ tween loop or an animation library pushing interpolated values through
277
+ signals is the single most expensive mistake available here - read
278
+ agents/performance.md before writing either.
279
+ Window state: onResize, onLayout, onWindowFocus, onWindowBlur exist, but
280
+ prefer the reactive reads (`env`/`capabilities` above, or the accessors
281
+ `windowSize()`, `safeArea()`, `displayScale()`, `windowFocused()`,
282
+ `keyboardHeight()`, `pointerLocked()`) for reading layout and window
283
+ state. For mouse look, `lockPointer(true)` enters relative mouse mode
284
+ (cursor hidden and confined, positions freeze) and pointer events keep
285
+ reporting motion through `movementX`/`movementY`.
286
+
287
+ - `createPortal` cannot mount during the app's initial render (it throws
288
+ "no mount target"): gate portal content behind a signal that starts false
289
+ and open it after startup - overlay content is opened, not born open.
290
+ `createScroll` containers need an explicit main-axis size (a height, or
291
+ flex inside a sized parent); with neither they resolve to 0 and the
292
+ content silently vanishes (`maxHeight` alone does not size it). The
293
+ runtime warns when this happens.
224
294
 
225
295
  - Device/GPU access via subpath imports: @solidrt/core/camera, /microphone,
226
296
  /speech, /gpu. Image flow: `decodeImage(bytes)` ->
@@ -253,5 +323,4 @@ render(() => <App />)
253
323
  Note the two `<d-rect>` underlays: a `<view>`/`<window>` does not paint, so a
254
324
  background is a draw-primitive child placed behind the content.
255
325
 
256
- To run and verify (incl. headless), see @solidrt/cli (its AGENTS.md). For
257
- higher-level components, see @solidrt/components (its AGENTS.md).
326
+ To run and verify (incl. headless), see @solidrt/cli (its AGENTS.md).
package/README.md CHANGED
@@ -53,7 +53,7 @@ Optionally, create a `tsconfig.json` to enable type recognition for SolidRT elem
53
53
 
54
54
  ## API
55
55
 
56
- See [docs/20-core](https://github.com/wellawaretech/solidrt/blob/main/docs/20-core/index.md) for the full API reference.
56
+ See [docs/](https://github.com/wellawaretech/solidrt/blob/main/packages/core/docs/index.md) (shipped in the package) for the full API reference.
57
57
 
58
58
  ## License
59
59
 
package/docs/index.md ADDED
@@ -0,0 +1,154 @@
1
+ # Core
2
+
3
+ `@solidrt/core` is the spine of SolidRT. It links SolidJS reactivity
4
+ to the native rendertree: an element vocabulary, layout, input, frames, and
5
+ the environment model for adapting to the device you are running on.
6
+
7
+ If you only learn one layer, learn this one. Extensions and tools are built
8
+ on it and are replaceable; Core is the part that changes least (SolidRT is
9
+ in alpha, so "least" is not "never").
10
+
11
+ ## Elements
12
+
13
+ There is no DOM. JSX elements are native rendertree nodes, and the
14
+ vocabulary is deliberately small:
15
+
16
+ | Element | Purpose |
17
+ | --- | --- |
18
+ | `window` | The app window. One per app, the root of the tree. |
19
+ | `view` | Layout and input. Boxes, flex containers, hit targets. |
20
+ | `text`, `span` | A shaped paragraph, and a styled run inside it. |
21
+ | `rect`, `oval`, `line`, `path` | Painted shapes. |
22
+ | `texture` | A GPU texture: a decoded image, a camera frame, a shader target. |
23
+
24
+ Layout and paint are separate jobs, which is the one place the vocabulary
25
+ diverges sharply from HTML. A `view` never paints, so there is no
26
+ `backgroundColor`; you put a `rect` behind the content, and by default a
27
+ shape fills the layout box it sits in:
28
+
29
+ ```tsx
30
+ <view padding={16} alignItems="center">
31
+ <rect color="#1b2440" radius={12} />
32
+ <text color="white">Boxed</text>
33
+ </view>
34
+ ```
35
+
36
+ Each painting element also has a detached twin: `d-view`, `d-rect`,
37
+ `d-path`, `d-text`, and so on. Detached elements are positioned by their
38
+ parent's coordinate system rather than by layout, so changing one costs no
39
+ reflow. Use them for anything that moves at animation frequency.
40
+
41
+ ## Reactivity
42
+
43
+ Props are reactive values, not snapshots. A signal read inside JSX
44
+ subscribes exactly one native property to exactly one signal, and an update
45
+ writes that property directly. Nothing re-renders, and there is no virtual
46
+ DOM to diff:
47
+
48
+ ```tsx
49
+ let [x, setX] = createSignal(0)
50
+
51
+ <d-rect x={x()} w={40} h={40} color="tomato" />
52
+ ```
53
+
54
+ The reactive and control-flow vocabulary comes from SolidJS 2.0 and is
55
+ re-exported from `@solidrt/core`, so an app imports everything from one
56
+ place: `createSignal`, `createMemo`, `createEffect`, `createStore`,
57
+ `onCleanup`, and the control-flow components `For`, `Show`, `Switch`,
58
+ `Match`, `Loading`, `Errored`.
59
+
60
+ Because props are values rather than accessors, the usual Solid rules apply:
61
+ do not destructure props, and read reactive values inside the expression
62
+ that uses them.
63
+
64
+ An error thrown while computing an element's props or a child expression is
65
+ contained at that element: it keeps its last good value, the error is logged
66
+ once with the node and source line, and the element recovers when the
67
+ expression computes again. An error nothing claims (a throwing effect, an
68
+ error during mount) replaces the app's window with an error window showing
69
+ the message and stack, with a Reset that retries; the reactive system keeps
70
+ running either way. `<Errored>` gives a subtree its own fallback.
71
+
72
+ ## Layout
73
+
74
+ Layout is flexbox, plus a line-based subset of CSS grid, over the whole
75
+ element tree. Prop names match CSS: `flexDirection`, `alignItems`,
76
+ `justifyContent`, `gap`, `padding`, `width`, `position`, `top`.
77
+
78
+ Units are simpler than CSS. A bare number is pixels; a percentage is
79
+ `pct(50)`, a branded value rather than a parsed string:
80
+
81
+ ```tsx
82
+ <view flexDirection="row" gap={8} padding={16}>
83
+ <view width={pct(50)} />
84
+ </view>
85
+ ```
86
+
87
+ `position` has `relative` and `absolute` only, and an absolute element does
88
+ not itself become a containing block: it resolves against the nearest
89
+ ancestor with `position="relative"`.
90
+
91
+ ## Input
92
+
93
+ Pointer, wheel, and key events are props on any element:
94
+ `onPointerDown`, `onPointerMove`, `onPointerUp`, `onPointerEnter`,
95
+ `onPointerLeave`, `onWheel`, `onKeyDown`, `onKeyUp`. Events travel from the
96
+ hit leaf up to the root, and `stopPropagation()` ends the walk. Key events
97
+ bubble the same way, starting at the focused node - or at the window root
98
+ when nothing is focused, so `onKeyDown` on the window is where app-global
99
+ shortcuts live.
100
+
101
+ Text entry goes to the focused node's `onTextInput`. Focusing a field never
102
+ raises the on-screen keyboard by itself - a tap on the field (or an explicit
103
+ `startTextInput()`) does, and never while a physical keyboard is attached.
104
+
105
+ Coordinates are logical points, so a handler reads the same numbers on a
106
+ high-density phone screen as on a desktop monitor.
107
+
108
+ ## Frames and animation
109
+
110
+ `onFrame(callback)` runs before every painted frame with the frame time in
111
+ ms, the frame count, and the display refresh rate; it returns a disposer and
112
+ cleans itself up with the reactive scope it was called in. Rendering is
113
+ demand-driven: the runtime does not spin a render loop when nothing changed,
114
+ so an idle app is genuinely idle.
115
+
116
+ ```tsx
117
+ let [t, setT] = createSignal(0)
118
+ onFrame((tick) => setT(tick))
119
+
120
+ <d-view rotate={t() / 1000}>...</d-view>
121
+ ```
122
+
123
+ ## Environment and devices
124
+
125
+ `env` and `capabilities` describe where the app is running: `env` is what
126
+ is observed (system theme, text scale, orientation, visibility, connected
127
+ input devices), `capabilities` what follows from it for behavior (hover,
128
+ touch, precise pointer, keyboard navigation, window size class). Which
129
+ runtime features exist on this build is `Flux.capabilities`, by name, never
130
+ by guessing from the OS.
131
+
132
+ Window-shaped values are reactive too: `windowSize()`, `safeArea()`,
133
+ `displayScale()`, `keyboardHeight()`, `windowFocused()`.
134
+
135
+ Device access follows the same reactive shape, as `create*` primitives
136
+ imported from Core subpaths rather than an imperative API:
137
+
138
+ ```tsx
139
+ import { createCamera } from "@solidrt/core/camera"
140
+
141
+ let camera = createCamera()
142
+
143
+ <texture src={camera.texture()} fit="cover" />
144
+ ```
145
+
146
+ The same pattern covers `@solidrt/core/microphone`, `/sound`,
147
+ `/speech-recognition`, `/text-input`, `/image`, `/color`, and `/gpu`.
148
+
149
+ ## Reference
150
+
151
+ The [reference](/core/reference/) covers the API by subject: the element
152
+ vocabulary, drawing, text, detached elements, layout, transforms, input,
153
+ shaders, the GPU module, and the shared types. It shows the shipped declarations themselves,
154
+ so it says exactly what your editor says.
@@ -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.