@nakednous/host 0.0.11 → 0.0.13

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 CHANGED
@@ -70,7 +70,7 @@ dependency first and an options object last, and registers with the context so
70
70
 
71
71
  | member | what it is |
72
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 |
73
+ | `createHost(canvas, opts)` | the context: `ndcZMin` (WEBGL default, or WEBGPU), `onFrame(dt, host)` for the host's own loop, `afterFrame(dt, host)` after the pointer flush — the frame's last draw, a pointer handler's included, where a WebGPU bridge submits its command encoder — `onSize(w, h, dpr)` for the bridge's buffer, `raf` / `caf` overrides |
74
74
  | `host.view` | the view bag — `mat4Proj` · `mat4View` · `mat4PV` · `mat4PVInv` · `mat4Eye`, `vp`, `ndcZMin`, `stale`; `set(P, V)`, `setCamera(cam)`, `resize(w, h)` |
75
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
76
  | `host.players` | the registry ticked each frame — `{ tick(dt) → boolean }`, removed on `false` |
@@ -116,6 +116,10 @@ one wrote:
116
116
  5. **draw** — the bridge reads the camera state, the handles' values, the tracks' paths.
117
117
  6. **labels tick** — world anchors projected through the current bag, transforms written.
118
118
  7. **pointer flush** — the press queue empties, released pointers leave.
119
+ 8. **the post-frame hook** — `afterFrame(dt, host)`, when it was given: the frame's last draw,
120
+ a pointer handler's included, so a WebGPU bridge submits its command encoder there. It is
121
+ the host's loop's step and nothing in external tick — there the caller writes the frame's
122
+ end — and `host.dispose()` clears it.
119
123
 
120
124
  `dt` is seconds, clamped to 50 ms so a stalled tab never integrates a leap.
121
125
 
@@ -126,6 +130,7 @@ one wrote:
126
130
  | seam | direction | contract |
127
131
  |---|---|---|
128
132
  | view bag | bridge → host | the bridge's `setCamera(cam)` also calls `host.view.setCamera(cam)`; without a host the bridge keeps its own matrices |
133
+ | frame end | host → bridge | `afterFrame(dt, host)` runs after `pointer.flush()`; a WebGPU bridge submits its command encoder there, and without the hook the application calls the bridge's `endFrame` itself |
129
134
  | external tick | adapter → host | `host.tick(dt)` from the adapter's predraw; `host.labels.tick()` after the adapter set `host.view` from renderer state |
130
135
  | proxies · locus | tree → host → bridge | constraint objects carry `proxy` and `locus`; the host tests, the bridge draws |
131
136
  | label anchors | tree → bridge → host | a generator writes `out.labels`; the bridge forwards each to `labels.set` |
package/dist/index.js CHANGED
@@ -3098,10 +3098,14 @@ function decodeRGBE(bytes, opts) {
3098
3098
  *
3099
3099
  * Two loop modes. With { onFrame } the host runs requestAnimationFrame
3100
3100
  * (overridable through { raf, caf }): each frame computes dt (clamped to
3101
- * 50 ms), ticks the players, calls onFrame(dt, host), then flushes the
3102
- * pointer source. Without it the application, or the p5 adapter from
3103
- * predraw, calls host.tick(dt) = players.tick(dt) and host.pointer.flush()
3104
- * once its consumers ran. Nothing else in the host cares who owns the loop.
3101
+ * 50 ms), ticks the players, calls onFrame(dt, host), flushes the pointer
3102
+ * source, then calls afterFrame(dt, host) when one was given — the frame's
3103
+ * last draw, a pointer handler's included, which is where a WebGPU bridge
3104
+ * submits its command encoder. Without it the application, or the p5
3105
+ * adapter from predraw, calls host.tick(dt) = players.tick(dt) and
3106
+ * host.pointer.flush() once its consumers ran: external tick gains no
3107
+ * frame end, so afterFrame belongs to the host's own loop. Nothing else in
3108
+ * the host cares who owns the loop.
3105
3109
  *
3106
3110
  * The frame order inside onFrame: install the camera (which fills
3107
3111
  * host.view), update handles or routers, fall through to the orbit when
@@ -3115,12 +3119,18 @@ const _now = () => (typeof performance !== 'undefined' && performance.now) ? per
3115
3119
  * Create the host context of a canvas.
3116
3120
  *
3117
3121
  * @param {HTMLCanvasElement} canvas
3118
- * @param {{ ndcZMin?:number, onFrame?:function(number, object):void, raf?:function,
3122
+ * @param {{ ndcZMin?:number, onFrame?:function(number, object):void,
3123
+ * afterFrame?:function(number, object):void, raf?:function,
3119
3124
  * caf?:function, onSize?:function(number, number, number):void }} [opts]
3120
3125
  * ndcZMin: the GPU API's NDC-z convention, WEBGL (default) or WEBGPU —
3121
3126
  * written once, never detected. onFrame: the host's own loop; absent,
3122
- * external-tick mode. onSize(width, height, dpr): the bridge's chance
3123
- * to resize its drawing buffer.
3127
+ * external-tick mode. afterFrame: called after the pointer source
3128
+ * flushes, so the frame's last draw — a pointer handler's included —
3129
+ * is behind it; the submit seam of a WebGPU bridge, which ends its
3130
+ * command encoder there. The host's loop only: an external tick has
3131
+ * no frame end but the one its caller writes. dispose() clears it.
3132
+ * onSize(width, height, dpr): the bridge's chance to resize its
3133
+ * drawing buffer.
3124
3134
  * @returns {object} The host.
3125
3135
  */
3126
3136
  function createHost(canvas, opts) {
@@ -3128,6 +3138,7 @@ function createHost(canvas, opts) {
3128
3138
  const t0 = _now();
3129
3139
  const constructs = new Set();
3130
3140
  let loop = null, observer = null, labels = null;
3141
+ let afterFrame = typeof o.afterFrame === 'function' ? o.afterFrame : null;
3131
3142
  const host = {
3132
3143
  canvas,
3133
3144
  width: 0, height: 0, dpr: 1,
@@ -3209,6 +3220,7 @@ function createHost(canvas, opts) {
3209
3220
 
3210
3221
  /** Stop the loop, disconnect the observer, remove every listener, dispose every construct. */
3211
3222
  dispose() {
3223
+ afterFrame = null;
3212
3224
  if (loop) loop.stop();
3213
3225
  for (const c of [...constructs]) { if (typeof c.dispose === 'function') c.dispose(); }
3214
3226
  constructs.clear();
@@ -3237,6 +3249,7 @@ function createHost(canvas, opts) {
3237
3249
  host.players.tick(dt);
3238
3250
  o.onFrame(dt, host);
3239
3251
  host.pointer.flush();
3252
+ if (afterFrame !== null) afterFrame(dt, host);
3240
3253
  },
3241
3254
  });
3242
3255
  loop.start();