@nakednous/host 0.0.1 → 0.0.3
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/README.md +109 -10
- package/dist/index.js +952 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# `@nakednous/host`
|
|
2
2
|
|
|
3
3
|
DOM transport for `@nakednous/tree` — pointer input with per-pointer capture, the interactive
|
|
4
|
-
handle controller and pointer router, players and a frame loop,
|
|
5
|
-
Gamepad), image and video sources, a DOM label overlay
|
|
4
|
+
handle controller and pointer router, players and a frame loop, helm and track factories, 6-DOF
|
|
5
|
+
device streams (WebHID, Gamepad), image and video sources, a DOM label overlay and the orbit —
|
|
6
|
+
**zero renderer**, pure vanilla DOM.
|
|
6
7
|
|
|
7
|
-
> **Status: 0.0.x.**
|
|
8
|
-
>
|
|
9
|
-
>
|
|
10
|
-
> and the orbit.
|
|
8
|
+
> **Status: 0.0.x.** The whole surface below is shipped. What a bridge draws (a handle's locus,
|
|
9
|
+
> a track's path, a helm's rig) lives in `twgl.tree` / `p5.tree`; the host only computes, through
|
|
10
|
+
> `@nakednous/tree`, and listens.
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -19,11 +19,19 @@ npm install @nakednous/host
|
|
|
19
19
|
|
|
20
20
|
```js
|
|
21
21
|
import { createHost } from '@nakednous/host'
|
|
22
|
+
import { createCamera, PLANE } from '@nakednous/tree'
|
|
22
23
|
|
|
23
|
-
const
|
|
24
|
-
host
|
|
24
|
+
const cam = createCamera({ eye: [0, 0, 10] })
|
|
25
|
+
const host = createHost(canvas, {
|
|
26
|
+
onFrame(dt) {
|
|
27
|
+
host.view.setCamera(cam) // the matrices every pick and label reads
|
|
28
|
+
if (!h.update()) orbit.update() // the handle gate falls through to the orbit
|
|
29
|
+
draw()
|
|
30
|
+
host.labels.tick()
|
|
31
|
+
},
|
|
32
|
+
})
|
|
25
33
|
const h = host.handle({ constraint: PLANE, normal: [0, 0, 1] })
|
|
26
|
-
|
|
34
|
+
const orbit = host.orbit(cam)
|
|
27
35
|
```
|
|
28
36
|
|
|
29
37
|
---
|
|
@@ -40,7 +48,7 @@ WebGL or WebGPU — it owns a canvas element's input and the frame clock, and ha
|
|
|
40
48
|
▼
|
|
41
49
|
twgl.tree · webgpu.tree ← bridge: the GPU, thinly
|
|
42
50
|
│
|
|
43
|
-
├── @nakednous/host ← this package: pointer, handles, tracks, helms, players, streams, media
|
|
51
|
+
├── @nakednous/host ← this package: pointer, handles, tracks, helms, players, streams, media, labels, orbit
|
|
44
52
|
│ │
|
|
45
53
|
│ └── @nakednous/tree
|
|
46
54
|
│
|
|
@@ -54,6 +62,97 @@ and nothing flows back into tree.
|
|
|
54
62
|
|
|
55
63
|
---
|
|
56
64
|
|
|
65
|
+
## The surface
|
|
66
|
+
|
|
67
|
+
One context per canvas. Every construct is a method on it, takes its one positional
|
|
68
|
+
dependency first and an options object last, and registers with the context so
|
|
69
|
+
`host.dispose()` releases everything.
|
|
70
|
+
|
|
71
|
+
| member | what it is |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `createHost(canvas, opts)` | the context: `ndcZMin` (WEBGL default, or WEBGPU), `onFrame(dt, host)` for the host's own loop, `onSize(w, h, dpr)` for the bridge's buffer, `raf` / `caf` overrides |
|
|
74
|
+
| `host.view` | the view bag — `mat4Proj` · `mat4View` · `mat4PV` · `mat4PVInv` · `mat4Eye`, `vp`, `ndcZMin`, `stale`; `set(P, V)`, `setCamera(cam)`, `resize(w, h)` |
|
|
75
|
+
| `host.pointer` | the pointer source — presses queued per frame, per-pointer entries with a move counter, claims that capture on the canvas, Esc cancel, `flush()` |
|
|
76
|
+
| `host.players` | the registry ticked each frame — `{ tick(dt) → boolean }`, removed on `false` |
|
|
77
|
+
| `host.width` · `host.height` · `host.dpr` | the canvas observer's logical size and pixel ratio |
|
|
78
|
+
| `host.dt` · `host.clock()` | last frame period and seconds since creation |
|
|
79
|
+
| `host.handle(opts)` | `Handle` — a draggable core constraint (`SPHERE` · `PLANE` · `AXIS` · `DIAL` · `VIEW`, or a contract object); `update()`, `value(out, opts)`, snap, hover, cancel, `from` |
|
|
80
|
+
| `host.router(handles, opts)` | `PointerRouter` — one shared pick over overlapping handles, nearest proxy wins; shared hover |
|
|
81
|
+
| `host.cameraHelm(cam, opts)` · `host.poseHelm(opts)` | a core `PoseHelm` on the players: body-fly a camera state, or integrate into a pose in `WORLD` · `EYE` · `SELF` · a mat4 and `bind()` a target |
|
|
82
|
+
| `host.poseTrack(opts)` · `host.cameraTrack(cam, opts)` | core tracks ticked while they play; `{ handles }` builds `TrackHandles`, one handle per keyframe |
|
|
83
|
+
| `host.hid(opts)` · `host.gamepad(opts)` | rate streams — `lin[3]` / `ang[3]` in raw device units, `bind(helm)` feeds it each tick; `available`, `connected` |
|
|
84
|
+
| `host.image(url)` · `host.video(opts)` · `host.raster(draw, w, h)` | texture sources — an `ImageBitmap`, a hidden `<video>` from a file or the camera with a `ready` promise, a Canvas2D drawing |
|
|
85
|
+
| `host.labels` · `host.hasLabels` | the label layer, created on first access — `set(id, text, x, y, z, opts)` at a world anchor, `setScreen(id, text, sx, sy, opts)` in canvas px, `{ frame: true }` for a label that lives one frame, `tick()`; `hasLabels` probes without creating |
|
|
86
|
+
| `host.orbit(cam, opts)` | the fall-through gesture — one pointer orbits, two pan and dolly, the wheel dollies; `update()` reports whether the camera moved; the vertical sense follows the bag's projection (y-up GL, y-flipped p5) |
|
|
87
|
+
| `host.tick(dt)` | external-loop mode: tick the players; the caller flushes the pointer once its consumers ran |
|
|
88
|
+
| `host.register(c)` · `host.unregister(c)` · `host.dispose()` | the lifecycle |
|
|
89
|
+
|
|
90
|
+
The module-level functions behind the methods are exported too (`createView`, `createPointer`,
|
|
91
|
+
`createPlayers`, `createLoop`, `observeCanvas`, `Handle`, `PointerRouter`, `cameraHelm`,
|
|
92
|
+
`poseHelm`, `helmBasis`, `poseTrack`, `cameraTrack`, `TrackHandles`, `createHid`,
|
|
93
|
+
`createGamepad`, `decodeSpaceNavigator`, `loadImage`, `createVideo`, `raster`, `createLabels`,
|
|
94
|
+
`createOrbit`), so an adapter can compose them on its own context.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## The frame
|
|
99
|
+
|
|
100
|
+
Two loop modes. With `{ onFrame }` the host runs `requestAnimationFrame`; without it the
|
|
101
|
+
application — or the p5 adapter from its `predraw` — calls `host.tick(dt)` and flushes the
|
|
102
|
+
pointer itself. Inside a frame the order is fixed, because each step reads what the previous
|
|
103
|
+
one wrote:
|
|
104
|
+
|
|
105
|
+
1. **players tick** — a playing track writes its camera state or pose, a helm integrates the
|
|
106
|
+
stream it was fed, a stream polls its device.
|
|
107
|
+
2. **install the camera** — `host.view.setCamera(cam)` (or `set(P, V)` from renderer state):
|
|
108
|
+
the matrices every pick, solve, label and orbit reads this frame.
|
|
109
|
+
3. **handles and routers update** — presses are picked, drags solved, claims taken.
|
|
110
|
+
4. **the orbit falls through** — `if (!h.update()) orbit.update()`: only unclaimed pointers
|
|
111
|
+
reach it.
|
|
112
|
+
5. **draw** — the bridge reads the camera state, the handles' values, the tracks' paths.
|
|
113
|
+
6. **labels tick** — world anchors projected through the current bag, transforms written.
|
|
114
|
+
7. **pointer flush** — the press queue empties, released pointers leave.
|
|
115
|
+
|
|
116
|
+
`dt` is seconds, clamped to 50 ms so a stalled tab never integrates a leap.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Seams
|
|
121
|
+
|
|
122
|
+
| seam | direction | contract |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| view bag | bridge → host | the bridge's `setCamera(cam)` also calls `host.view.setCamera(cam)`; without a host the bridge keeps its own matrices |
|
|
125
|
+
| external tick | adapter → host | `host.tick(dt)` from the adapter's predraw; `host.labels.tick()` after the adapter set `host.view` from renderer state |
|
|
126
|
+
| proxies · locus | tree → host → bridge | constraint objects carry `proxy` and `locus`; the host tests, the bridge draws |
|
|
127
|
+
| label anchors | tree → bridge → host | a generator writes `out.labels`; the bridge forwards each to `labels.set` |
|
|
128
|
+
| rate stream | host → tree | `helm.feed(lin, ang)` per tick, raw device units; the helm's profile scales |
|
|
129
|
+
| camera state | host ↔ tree ↔ bridge | plain data: the orbit, a track, a helm write it; `setCamera(cam)` reads it |
|
|
130
|
+
| bridge camera | host → bridge | a camera helm or track exposes `_onApply(cam)`, fired after each write, for an adapter that mirrors the state into its own camera |
|
|
131
|
+
| construction | host → bridge | `TrackHandles` builds members through `_makeHandle(opts)` / `_makeRouter(opts)`, so a subclass makes members it can draw |
|
|
132
|
+
| device interfaces | test → host | `hid`, `gamepads`, `document`, `media`, `raf` / `caf` options replace the globals |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Conventions
|
|
137
|
+
|
|
138
|
+
- Options object last; the context's factories take their one positional dependency first.
|
|
139
|
+
- Out-first, zero allocation in every per-frame path: `value(out, …)`, the streams' triples,
|
|
140
|
+
the label positions, the view bag's matrices — caller- or host-owned buffers allocated once.
|
|
141
|
+
- Every DOM listener attached by the context is removed by `dispose()`.
|
|
142
|
+
- Errors are `console.error` with a `[host]` prefix and a fallback, never a throw.
|
|
143
|
+
- Library code: semicolons, JSDoc on every public member, `@module host/<file>`.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm test # node:test — DOM pieces against a minimal stub, math through tree
|
|
151
|
+
npm run build # rollup → dist/index.js
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
57
156
|
## License
|
|
58
157
|
|
|
59
158
|
AGPL-3.0-only
|