@maxenve/ren-three 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +307 -2
- package/package.json +51 -4
- package/src/index.js +1633 -0
- package/src/surface.js +204 -0
- package/types/index.d.ts +473 -0
- package/types/surface.d.ts +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wilton Lazary
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,308 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ren-three
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The three.js renderer for [ren-core](https://github.com/wiltonlazary/ren-core): a ren-core `Host`
|
|
4
|
+
(`ren-core/host`) over a three.js scene graph. JSX describes the scene; rrx-core
|
|
5
|
+
signals drive it; ren-core's control flow (`Show`, `For`, `Choose`, `Render`,
|
|
6
|
+
`Pending`, `Recover`) adds and removes objects. Plain JavaScript with JSDoc
|
|
7
|
+
types, strict `tsc` checking and generated declarations.
|
|
8
|
+
|
|
9
|
+
The package is published on npm as `@maxenve/ren-three` under the MIT license;
|
|
10
|
+
install it under its import name: `npm install ren-three@npm:@maxenve/ren-three`.
|
|
11
|
+
Its runtime dependencies are ren-canv and ren-core (linked from
|
|
12
|
+
the sibling checkouts); three.js is a peer
|
|
13
|
+
the caller imports and passes in (`>=0.160`; tested with 0.186.1), so the
|
|
14
|
+
application decides how it loads (ren-show loads it as a chunk of its
|
|
15
|
+
own on first use). It can share a page with ren-dom and ren-skia: each
|
|
16
|
+
application root has its own renderer.
|
|
17
|
+
|
|
18
|
+
```jsx
|
|
19
|
+
import * as THREE from 'three';
|
|
20
|
+
import { Root, $signal, $read, $write, $active, For } from 'ren-core';
|
|
21
|
+
import { $dom } from 'ren-dom';
|
|
22
|
+
import { $three, $animate } from 'ren-three';
|
|
23
|
+
|
|
24
|
+
const Lantern = () => {
|
|
25
|
+
const lit = $signal($active(), false);
|
|
26
|
+
let globe = null;
|
|
27
|
+
$animate(frame => (globe.position.y = Math.sin(frame.time) * 0.2));
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
<hemisphereLight intensity={0.6} />
|
|
31
|
+
<pointLight position={[0, 2, 3]} intensity={() => ($read(lit) ? 30 : 5)} />
|
|
32
|
+
<mesh ref={m => (globe = m)} onClick={() => $write(lit, !$read(lit))}>
|
|
33
|
+
<sphereGeometry params={[0.7, 32, 16]} />
|
|
34
|
+
<meshPhongMaterial color={() => ($read(lit) ? '#ffd166' : '#5b6c8f')} shininess={60} />
|
|
35
|
+
</mesh>
|
|
36
|
+
<For each={[-1.2, 0, 1.2]}>
|
|
37
|
+
{x => <mesh position={() => [x(), -1.4, 0]}><cylinderGeometry params={[0.15, 0.2, 0.6]} /><meshNormalMaterial /></mesh>}
|
|
38
|
+
</For>
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
Root({ id: 'stage', target: document.body, renderer: $three(THREE, { width: 640, height: 360 }), children: <Lantern /> });
|
|
44
|
+
// Nested in a DOM view, fed by props: <Root id="stage" renderer={$three(THREE)} props={…}>{() => <Scene />}</Root>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
| Export | What |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `$three(THREE, options)` | the renderer (a `Renderer`): the Host, its `scene` and `camera`, `frame(time)`, `resize(w, h)`, `pick(x, y)`, `dispatch(type, x, y)`, and `dragOver(x, y, files, types)`, `dragLeave()`, `dropFiles(x, y, files)` |
|
|
50
|
+
| `render(view, renderer, options)` | `mount` into the renderer's scene; returns the dispose function |
|
|
51
|
+
| `$animate(fn)` | in a component: runs `fn(frame)` before every frame while the component lives (`frame.time`, `frame.delta` in seconds, `frame.scene`, `frame.camera`, `frame.renderer`) |
|
|
52
|
+
| `CONSTRUCT` | the props `element` reads at creation; a worker passes it to `serve` |
|
|
53
|
+
| `loadLayout`, `remoteLayout` | the primitives' layout engine: load it once; lay out in a worker |
|
|
54
|
+
| `loadShaper` | the primitives' text shaper (HarfBuzz): in a browser, load it once with the URL of harfbuzzjs's `harfbuzz.wasm`; node loads it when text first needs it |
|
|
55
|
+
| `Renderer`, `Tick` | the classes |
|
|
56
|
+
|
|
57
|
+
## Elements
|
|
58
|
+
|
|
59
|
+
- **Tags are three.js classes.** A lowercase element is the class of the
|
|
60
|
+
same name, capitalized, from the namespace passed to `$three`: `<mesh>`,
|
|
61
|
+
`<group>`, `<boxGeometry>`, `<meshStandardMaterial>`, `<ambientLight>`,
|
|
62
|
+
`<perspectiveCamera>`, `<instancedMesh>`, … An unknown name throws.
|
|
63
|
+
`<existing of={made}>` places an object made elsewhere (and leaves
|
|
64
|
+
its disposal to its owner unless `dispose` is true).
|
|
65
|
+
- **A host node is the three.js object itself**, with ren-core's record on it
|
|
66
|
+
under `__ren`; a `ref` receives the object.
|
|
67
|
+
- **Construction.** `params` are the constructor's arguments, compiled or not
|
|
68
|
+
(the Host's `construct` props). New params (a different list of values)
|
|
69
|
+
rebuild the object in place: it keeps its identity, parent and handlers; a
|
|
70
|
+
fresh one is made and copied in (a scene object takes only what its class
|
|
71
|
+
sets beyond Object3D's fields, never its transform or children; a
|
|
72
|
+
geometry frees its old GPU buffers), and the properties the view set apply
|
|
73
|
+
again. A class without `copy` needs a keyed element (a `Show` or a `For`
|
|
74
|
+
row) to make a new one.
|
|
75
|
+
- **Slots.** Geometries go into the parent's `geometry`, materials into
|
|
76
|
+
`material`, fog into `fog`, and `slot="name"` into any other property;
|
|
77
|
+
removal restores the previous value. Other objects are added as children.
|
|
78
|
+
- **Properties** are set by name. A dash sets a path (`position-x`,
|
|
79
|
+
`rotation-y`). A property holding a math object (Vector3, Euler,
|
|
80
|
+
Color, Quaternion, …) is updated in place: an array spreads into `set`,
|
|
81
|
+
the same type is copied, a number is a Color's hex or goes to `setScalar`,
|
|
82
|
+
anything else to `set` (`color="#f80"`, `scale={2}`). Reactive values bind
|
|
83
|
+
as everywhere in ren-core.
|
|
84
|
+
- **Resources.** A removed object's geometries, materials and textures are
|
|
85
|
+
disposed at the end of the flush, unless it was inserted again meanwhile
|
|
86
|
+
(a moved row). `dispose={null}` on a geometry, material or texture
|
|
87
|
+
element keeps that resource; on an object it skips only that object's own
|
|
88
|
+
`dispose()`, and the resources of its elements still go.
|
|
89
|
+
- **`<gl>`** sets the WebGL renderer's own properties from the view
|
|
90
|
+
(`<gl toneMapping={ACESFilmicToneMapping} toneMappingExposure={1.2}
|
|
91
|
+
shadowMap-enabled />`): kept, applied to the renderer as it is made, and
|
|
92
|
+
reactive like any property.
|
|
93
|
+
- **Cursor.** `cursor="pointer"` on an object shows that CSS cursor while
|
|
94
|
+
the pointer is over it or a child (where no primitive is on top).
|
|
95
|
+
- **Camera.** A PerspectiveCamera by default (`camera` option), sized to the
|
|
96
|
+
canvas; `<perspectiveCamera main>` in the view replaces it.
|
|
97
|
+
- **Portable primitives render too** (`View`, `Layout`, `Scroll`, `Label`,
|
|
98
|
+
`Edit`, `Action`, `Image`, `Shape`), through
|
|
99
|
+
[ren-canv](https://github.com/wiltonlazary/ren-canv): the same layout, portable style,
|
|
100
|
+
editing, text selection, native text entry and accessibility mirror as on
|
|
101
|
+
ren-skia, drawn with a 2D canvas into a texture. An application of
|
|
102
|
+
primitives alone runs here as on ren-dom or ren-skia, and mixes freely
|
|
103
|
+
with three.js objects:
|
|
104
|
+
- **The overlay.** Primitives placed in the scene itself lie over the
|
|
105
|
+
canvas, pixel for pixel, drawn after the scene; in the order of the
|
|
106
|
+
view among the scene's objects.
|
|
107
|
+
- **Panels.** Primitives placed in a three.js object (`<group>`,
|
|
108
|
+
`<mesh>`) become a plane in it, as large as their content (`pixel`
|
|
109
|
+
world units per pixel, 0.01), facing +z.
|
|
110
|
+
- **Input.** The pointer reaches the overlay first, then a panel under
|
|
111
|
+
it (by the raycast's texture coordinate; a drag stays with the surface
|
|
112
|
+
it started on), then the scene's objects, so a press on a button never
|
|
113
|
+
also clicks the mesh behind it. Keys, copy and select all go to the
|
|
114
|
+
surface last pressed; an Edit's native text entry lies over it on the
|
|
115
|
+
canvas (a panel's projected). A touch follows the `touchAction` of
|
|
116
|
+
the primitives under it on the surface it presses (the overlay where
|
|
117
|
+
it has something there, else a panel), as ren-canv's attach does: its
|
|
118
|
+
start is cancelled where they allow no pan, its first move where it
|
|
119
|
+
goes along an axis they forbid, a second finger where they forbid a
|
|
120
|
+
pinch zoom; where none sets one, a touch that a surface or an object
|
|
121
|
+
with a handler took keeps the page from panning. When the browser
|
|
122
|
+
takes the pointer back (a `pointercancel`), the surface holding the
|
|
123
|
+
press hears `onPointerCancel` where the pointer last was and the press
|
|
124
|
+
ends with no `pointerup`; with no surface holding it, the scene's
|
|
125
|
+
objects there hear `pointercancel` through the raycast.
|
|
126
|
+
- **Drag and drop.** Files dragged over the canvas go to the surfaces as
|
|
127
|
+
presses do: the overlay where it has something there or an item that
|
|
128
|
+
hears drags or drops, else a panel by the raycast's texture coordinate.
|
|
129
|
+
Its items hear `onDragEnter`, `onDragOver`, `onDragLeave` and `onDrop`
|
|
130
|
+
(`{ files, x, y }` in its pixels) as on ren-canv; a drag moving to
|
|
131
|
+
another surface leaves the first, then enters the second, and leaving
|
|
132
|
+
the canvas leaves the one under it; a drop ends the drag without a
|
|
133
|
+
leave. The browser's default (opening a dropped file) is prevented only
|
|
134
|
+
where a surface or a scene object takes the drag. Main thread only.
|
|
135
|
+
- They need the `font` option: the typeface's bytes, which measure the
|
|
136
|
+
text (from the font file itself) and draw it (registered as a
|
|
137
|
+
FontFace); `families` and `fallback` add typefaces by family name and
|
|
138
|
+
for the characters a typeface lacks, measured and registered the same
|
|
139
|
+
way. A character no typeface has measures as the missing glyph, but the
|
|
140
|
+
2D canvas draws it in the browser's fallback font, at another width.
|
|
141
|
+
Right-to-left text is laid out by ren-canv's bidirectional algorithm;
|
|
142
|
+
the 2D canvas sets each right-to-left run from its right edge in its
|
|
143
|
+
visual order. Text that needs shaping (Arabic joined, Indic clusters,
|
|
144
|
+
marks) is measured shaped (ren-canv's `loadShaper`: in a browser, load
|
|
145
|
+
it once with the URL of harfbuzzjs's `harfbuzz.wasm`) and the browser
|
|
146
|
+
shapes what it draws with the same features (kerning and optional
|
|
147
|
+
ligatures off), at the width measured. A three.js object inside a
|
|
148
|
+
primitive throws.
|
|
149
|
+
- **Surfaces.** Each is a ren-canv Document: `renderer.overlay` is the
|
|
150
|
+
overlay's (null until a primitive is placed in the scene) and
|
|
151
|
+
`renderer.surfaces` holds the overlay's and every panel's, with the
|
|
152
|
+
Document's API (`commands()`, `copied()`, `press`, `key`, …). Pointer
|
|
153
|
+
events, keys, focus, scrolling and the cursor behave as on the DOM
|
|
154
|
+
(ren-canv's README, "Input as the DOM has it"). A root's `$keys` and
|
|
155
|
+
`$scrolls` (listened on the scene) hear every surface: the overlay's
|
|
156
|
+
and each panel's keys, chords too, and scrolls; a key with no surface
|
|
157
|
+
focused goes to the overlay (else the first panel). One surface has
|
|
158
|
+
the focus: a press, an item's `focus()` or `focusFirst()` and
|
|
159
|
+
`$focus(ref)` take it from the others, and the keys go there; a blur
|
|
160
|
+
handler there that moves the focus wins, in whichever surface, as in
|
|
161
|
+
Chrome.
|
|
162
|
+
- **Theme.** `renderer.setTheme(tokens)` takes a new theme at once for the
|
|
163
|
+
overlay and every panel; the scene and all state stay.
|
|
164
|
+
- **Viewport.** In a three.js root `$viewport()` and `$media()` read the
|
|
165
|
+
canvas's size in CSS pixels, followed as it resizes, not the page's
|
|
166
|
+
window; the dark color scheme and reduced motion come from the
|
|
167
|
+
window the canvas is in (none without one). In worker mode the
|
|
168
|
+
connection carries them to the worker (ren-core's README, "Viewport
|
|
169
|
+
and media queries"). In a panel whose primitive sets its width and
|
|
170
|
+
height in pixels (its style's `width` and `height`, or the `width` and
|
|
171
|
+
`height` props), they read the panel's size, followed as it changes;
|
|
172
|
+
the preferences stay the window's. A panel sized by its content reads
|
|
173
|
+
the canvas's: its size follows what it shows, so a view reading it
|
|
174
|
+
could swing between two layouts. The Host's `viewportOf` gives each
|
|
175
|
+
primitive this source, bound to its panel once the primitive is
|
|
176
|
+
placed (a component runs before its nodes are), the canvas's until
|
|
177
|
+
then; in worker mode the connection carries the panel's too.
|
|
178
|
+
|
|
179
|
+
## Frames
|
|
180
|
+
|
|
181
|
+
Rendering is on demand: a flush that changed the scene asks for one frame
|
|
182
|
+
(`requestAnimationFrame`), and an unchanged flush draws nothing. While any
|
|
183
|
+
`$animate` callback lives, every animation frame runs the callbacks and
|
|
184
|
+
renders. `schedule: false` leaves frames to the caller (`frame(time)`), for
|
|
185
|
+
tests and hosts with their own loop.
|
|
186
|
+
|
|
187
|
+
## Events
|
|
188
|
+
|
|
189
|
+
`on<Name>` handlers on any object receive raycast pointer events: `click`,
|
|
190
|
+
`dblclick`, `contextmenu`, `pointerdown`, `pointerup`, `pointermove`,
|
|
191
|
+
`pointercancel` (the browser took the pointer back; where it last was),
|
|
192
|
+
`wheel`, and `pointerover`/`pointerout` as the objects under the pointer
|
|
193
|
+
change. Files dragged over the canvas where no primitive takes them reach
|
|
194
|
+
`onDragOver` (with `files`, their count, and `types`) and `onDrop`
|
|
195
|
+
(`files`, the dropped File objects) on the objects under them. The nearest hit's handler runs first, then its ancestors', until one
|
|
196
|
+
calls `stopPropagation()`. The event carries `object` (hit), `currentObject`
|
|
197
|
+
(the handler's), `point`, `distance`, `intersection`, `intersections` and
|
|
198
|
+
`native`. The pointer is read in the canvas's drawn pixels, so a canvas
|
|
199
|
+
the page's CSS resizes still picks what is under it. An object that is
|
|
200
|
+
not drawn (`visible={false}` on it or an ancestor) takes no pointer, as a
|
|
201
|
+
hidden element on the DOM; a catcher that must take it without showing
|
|
202
|
+
stays visible with `colorWrite={false} depthWrite={false}`. Handlers run as a `$batch` in the context they were bound in, as
|
|
203
|
+
everywhere in ren-core. The raycast runs only while some object has a handler or a cursor.
|
|
204
|
+
|
|
205
|
+
## Layout
|
|
206
|
+
|
|
207
|
+
The primitives are laid out by ren-canv's engine, Taffy by default: `await
|
|
208
|
+
loadLayout()` once before the first renderer that draws them (in a browser,
|
|
209
|
+
with the URL of taffy-layout's `taffy_wasm_bg.wasm`). Or in a worker:
|
|
210
|
+
`layout: remoteLayout(worker)`, with `serveLayout` from `ren-canv/worker`
|
|
211
|
+
there; the overlay and every panel lay out there and paint when their boxes
|
|
212
|
+
come back.
|
|
213
|
+
|
|
214
|
+
## Options
|
|
215
|
+
|
|
216
|
+
| Option | Meaning |
|
|
217
|
+
| --- | --- |
|
|
218
|
+
| `width`, `height` | the canvas in CSS pixels; by default the host element's size, followed as it resizes (300 × 150 without one) |
|
|
219
|
+
| `scale` | the device pixel ratio (the window's) |
|
|
220
|
+
| `renderer` | what draws: a `WebGLRenderer` made on the canvas by default (antialiased); or one given, or a function of the canvas that makes it (a WebGPU renderer, a stub in tests) |
|
|
221
|
+
| `camera` | a three.js camera, or `{ fov, near, far, position }` for the default PerspectiveCamera (50°, 0.1, 1000, at [0, 0, 5]) |
|
|
222
|
+
| `background` | the scene's background color |
|
|
223
|
+
| `schedule` | `'frame'` (default): frames on `requestAnimationFrame`; `false`: only when `frame()` is called |
|
|
224
|
+
| `font` | the typeface's bytes for the primitives (needed once one renders) |
|
|
225
|
+
| `mono` | a monospace typeface's bytes: text whose `fontFamily` names monospace is measured and drawn in it |
|
|
226
|
+
| `families` | typefaces' bytes by family name: text whose `fontFamily` names one (the first of its list given here, before a generic family) is measured and drawn in it |
|
|
227
|
+
| `fallback` | typefaces' bytes, in order: a character a typeface lacks is measured and drawn in the first of them that has it |
|
|
228
|
+
| `pixel` | world units per pixel of a panel (0.01) |
|
|
229
|
+
| `theme` | theme overrides for the primitives (ren-core's tokens) |
|
|
230
|
+
| `aria` | the primitives' accessibility mirror, as ren-canv's (`true`, `false`, `'demand'`) |
|
|
231
|
+
| `layout` | where the primitives are laid out: this thread (default), or a layout worker, `remoteLayout(port)` |
|
|
232
|
+
| `image` | loads an `Image` source for a 2D canvas (an HTMLImageElement by default) |
|
|
233
|
+
|
|
234
|
+
An application root in a document makes a `<canvas>` in its host element and
|
|
235
|
+
routes its pointer events; `close` (the root's dispose) empties the scene,
|
|
236
|
+
disposes its resources and the WebGL renderer, and removes the canvas.
|
|
237
|
+
|
|
238
|
+
## Worker mode
|
|
239
|
+
|
|
240
|
+
As with ren-dom and ren-skia, three.js and the scene stay on the main
|
|
241
|
+
thread, with the renderer; the worker holds only the application and its
|
|
242
|
+
components (no three.js, no DOM, no renderer code).
|
|
243
|
+
|
|
244
|
+
```jsx
|
|
245
|
+
// worker.jsx: the application only
|
|
246
|
+
import { serve } from 'ren-core/worker';
|
|
247
|
+
import { CONSTRUCT } from 'ren-three';
|
|
248
|
+
serve(() => <Scene />, { id: 'stage', construct: CONSTRUCT });
|
|
249
|
+
|
|
250
|
+
// main.jsx: three.js and the renderer
|
|
251
|
+
import * as THREE from 'three';
|
|
252
|
+
Root({ id: 'stage', runtime: 'worker', worker: () => new Worker(url, { type: 'module' }), target, renderer: $three(THREE) });
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
- `construct: CONSTRUCT` sends each element's constructor `params` (and
|
|
256
|
+
`slot`, `dispose`) with it, and each compiled template instance's, so
|
|
257
|
+
the main thread builds the same objects. `<existing of>` holds an
|
|
258
|
+
object made on the main thread, so it belongs to the direct runtime.
|
|
259
|
+
- `$animate` runs in the worker on its own frames, with a `Tick` whose
|
|
260
|
+
renderer, scene and camera are null: animate through signals
|
|
261
|
+
(`rotation-y={angle}`), whose writes cross like any update.
|
|
262
|
+
- Pointer events are raycast on the main thread and cross with their canvas
|
|
263
|
+
`x` and `y`, buttons and modifier keys; refs in the worker are handles.
|
|
264
|
+
- Importing `CONSTRUCT` and `$animate` brings no renderer code into a worker
|
|
265
|
+
bundle (`$animate` recognizes the renderer by its shape).
|
|
266
|
+
|
|
267
|
+
## Tests
|
|
268
|
+
|
|
269
|
+
```sh
|
|
270
|
+
(cd ../../../rrx-core/wtree/_repo_ && npm install) # rrx-core, ren-core, ren-canv, then ren-dom: their installs generate the types checked here
|
|
271
|
+
(cd ../../../ren-core/wtree/_repo_ && npm install)
|
|
272
|
+
(cd ../../../ren-canv/wtree/_repo_ && npm install)
|
|
273
|
+
(cd ../../../ren-dom/wtree/_repo_ && npm install)
|
|
274
|
+
npm install # ren-core, rrx-core, ren-canv and ren-dom (linked), pinned devDependencies: three, esbuild, happy-dom, typescript
|
|
275
|
+
npm test # declarations, tsc --checkJs --strict, the TypeScript consumer, node:test twice
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
`test/three.test.jsx` builds and raycasts real three.js scenes in node (no
|
|
279
|
+
WebGL: a drawer stub counts frames): classes, params, slots and
|
|
280
|
+
properties; reactive properties and regions with one render per changed
|
|
281
|
+
flush; resource disposal of removed objects, not of moved ones or
|
|
282
|
+
`<existing>` ones; raycast events with bubbling and hover; `$animate`; a
|
|
283
|
+
`main` camera and resizing; the refusals; and a three.js root nested
|
|
284
|
+
in a ren-dom view with props; and worker mode (the application served over
|
|
285
|
+
a MessageChannel: params, props, raycast clicks answered by the worker,
|
|
286
|
+
`$animate` in the worker). ren-show checks both on WebGL in headless
|
|
287
|
+
Chrome, the worker mode with a real Worker. `test/primitives.test.jsx`
|
|
288
|
+
renders the portable primitives through ren-canv, in the overlay and on a
|
|
289
|
+
panel: their layout, text, input and a layout worker.
|
|
290
|
+
`test/viewport.test.jsx` checks `$viewport` and `$media` against the
|
|
291
|
+
canvas's size as it resizes, directly and in worker mode.
|
|
292
|
+
`test/deps.test.js` checks that `src/` reaches no module a dependent does not install.
|
|
293
|
+
`test/timers.test.js` fails a timer call that does not say why it is one,
|
|
294
|
+
and `test/exports.test.js` locks the public contract to
|
|
295
|
+
`test/exports.lock.json`. `npm test` runs the
|
|
296
|
+
suites with the automatic runtime (`ren-core/loader`) and compiled by
|
|
297
|
+
ren-core/esbuild (`ren-core/compiled`).
|
|
298
|
+
|
|
299
|
+
## Benchmarks
|
|
300
|
+
|
|
301
|
+
The harnesses live in [ren-bench](https://github.com/wiltonlazary/ren-bench).
|
|
302
|
+
Run benchmark commands from that checkout.
|
|
303
|
+
|
|
304
|
+
[ren-bench's three.js benchmark](https://github.com/wiltonlazary/ren-bench/blob/main/bench/r3f/README.md) measures ren-three
|
|
305
|
+
against a market renderer on the same scene
|
|
306
|
+
(1,000 meshes in a keyed list, created, recolored, reordered, removed), as
|
|
307
|
+
each library's users write it; its README has the method and the current
|
|
308
|
+
results.
|
package/package.json
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maxenve/ren-three",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "The three.js renderer for ren-core: JSX over a three.js scene graph, with raycast events, on-demand rendering and a frame loop.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/wiltonlazary/ren-three.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/wiltonlazary/ren-three#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/wiltonlazary/ren-three/issues"
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22.15"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"src",
|
|
21
|
+
"types",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"types": "./types/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./types/index.d.ts",
|
|
28
|
+
"default": "./src/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"types": "node scripts/types.mjs",
|
|
33
|
+
"check": "tsc -p tsconfig.json",
|
|
34
|
+
"test": "node scripts/types.mjs && tsc -p tsconfig.json && tsc -p test/types/tsconfig.json && node --import ren-core/loader --test test/*.test.js test/*.test.jsx && node --import ren-core/compiled --test test/*.test.jsx",
|
|
35
|
+
"prepare": "node scripts/types.mjs",
|
|
36
|
+
"prepack": "node scripts/types.mjs"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"ren-canv": "npm:@maxenve/ren-canv@0.1.1",
|
|
40
|
+
"ren-core": "npm:@maxenve/ren-core@0.1.1"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"three": ">=0.160"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"esbuild": "0.28.2",
|
|
47
|
+
"happy-dom": "20.14.5",
|
|
48
|
+
"ren-dom": "npm:@maxenve/ren-dom@0.1.1",
|
|
49
|
+
"rrx-core": "npm:@maxenve/rrx-core@0.1.1",
|
|
50
|
+
"three": "0.186.1",
|
|
51
|
+
"typescript": "7.0.2"
|
|
52
|
+
}
|
|
53
|
+
}
|