@downdraft/engine 0.1.2-alpha.5 → 0.3.0
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/app/src/renderer/bootstrap.ts +1 -1
- package/app/src/renderer/feature-log.ts +1 -1
- package/core/src/index.ts +2 -2
- package/core/src/input/local-player-manager.ts +2 -2
- package/core/src/platform/rpc.ts +4 -1
- package/core/src/render/game-renderer.ts +127 -64
- package/core/src/sab/grid-buffer.ts +55 -2
- package/core/src/sab/record-buffer.ts +48 -5
- package/core/src/sab/sim-channel.ts +181 -17
- package/core/src/sab/slot-buffer.ts +55 -1
- package/core/src/sab/types.ts +11 -0
- package/core/src/telemetry/gpu-resource-tracker.ts +24 -0
- package/core/src/util/index.ts +1 -0
- package/core/src/util/logger.ts +2 -2
- package/core/src/util/session-timer.ts +23 -0
- package/core/src/worker/base-worker-host.ts +2 -1
- package/core/src/worker/buffer-sync.ts +20 -13
- package/core/src/worker/rpc.ts +54 -5
- package/core/src/worker/sim-worker-base.ts +6 -3
- package/core/src/worker/task-pool.ts +4 -0
- package/dist/.dd-manifest.json +879 -869
- package/dist/app/src/renderer/bootstrap.js +1 -1
- package/dist/app/src/renderer/feature-log.js +1 -1
- package/dist/core/src/index.js +2 -2
- package/dist/core/src/input/local-player-manager.js +2 -2
- package/dist/core/src/platform/rpc.js +2 -1
- package/dist/core/src/render/game-renderer.js +125 -59
- package/dist/core/src/sab/grid-buffer.js +53 -1
- package/dist/core/src/sab/record-buffer.js +49 -5
- package/dist/core/src/sab/sim-channel.js +173 -17
- package/dist/core/src/sab/slot-buffer.js +54 -1
- package/dist/core/src/telemetry/gpu-resource-tracker.js +26 -0
- package/dist/core/src/util/index.js +1 -0
- package/dist/core/src/util/logger.js +2 -2
- package/dist/core/src/util/session-timer.js +22 -0
- package/dist/core/src/worker/base-worker-host.js +2 -1
- package/dist/core/src/worker/buffer-sync.js +16 -9
- package/dist/core/src/worker/rpc.js +46 -8
- package/dist/core/src/worker/sim-worker-base.js +6 -3
- package/dist/core/src/worker/task-pool.js +5 -0
- package/dist/libraries/devtools/src/backend.js +35 -9
- package/dist/libraries/devtools/src/collectors.js +73 -22
- package/dist/libraries/gamepad/src/feed-input.js +1 -1
- package/dist/libraries/gamepad/src/hub.js +2 -2
- package/dist/libraries/gamepad/src/source-sab.js +2 -2
- package/dist/libraries/gamepad/src/sysfs-enrich.js +2 -2
- package/dist/libraries/gpu-kernels/src/kernel.js +1 -1
- package/dist/libraries/gpu-kernels/src/transpile.js +1 -1
- package/dist/libraries/html-ui-kit/src/nav/nav-controller.js +1 -1
- package/dist/libraries/html-ui-kit/src/nav/nav-input.js +2 -2
- package/dist/libraries/networking/src/discovery.js +8 -8
- package/dist/libraries/persistence/src/file-save-store.js +5 -5
- package/dist/libraries/persistence/src/opfs-save-store.js +2 -2
- package/dist/modules/controller-ui/src/index.js +1 -1
- package/dist/modules/devtools/src/blitz/fonts.js +75 -0
- package/dist/modules/devtools/src/blitz/host.js +127 -33
- package/dist/modules/devtools/src/blitz/panels/console.js +19 -7
- package/dist/modules/devtools/src/blitz/panels/elements.js +217 -28
- package/dist/modules/devtools/src/blitz/panels/gpu.js +5 -2
- package/dist/modules/devtools/src/blitz/panels/performance.js +28 -14
- package/dist/modules/devtools/src/blitz/panels/snapshot.js +31 -8
- package/dist/modules/devtools/src/blitz/panels/types.js +2 -1
- package/dist/modules/devtools/src/blitz/theme.js +26 -4
- package/dist/modules/html-ui/src/doc-backend.js +52 -3
- package/dist/modules/html-ui/src/host.js +6 -3
- package/dist/modules/html-ui/src/jsx-runtime.js +1 -1
- package/libraries/blitz-ui/native/Cargo.toml +6 -0
- package/libraries/blitz-ui/native-osr/Cargo.toml +3 -1
- package/libraries/devtools/src/backend.ts +38 -12
- package/libraries/devtools/src/collectors.ts +75 -22
- package/libraries/gamepad/src/feed-input.ts +1 -1
- package/libraries/gamepad/src/hub.ts +2 -2
- package/libraries/gamepad/src/source-sab.ts +2 -2
- package/libraries/gamepad/src/sysfs-enrich.ts +2 -2
- package/libraries/gpu-kernels/src/kernel.ts +2 -2
- package/libraries/gpu-kernels/src/transpile.ts +1 -1
- package/libraries/html-ui-kit/src/nav/nav-controller.ts +1 -1
- package/libraries/html-ui-kit/src/nav/nav-input.ts +2 -2
- package/libraries/networking/src/discovery.ts +8 -8
- package/libraries/persistence/src/file-save-store.ts +5 -5
- package/libraries/persistence/src/opfs-save-store.ts +2 -2
- package/libraries/physics-rapier/src/realm-worker-script.ts +1 -1
- package/modules/controller-ui/src/index.ts +1 -1
- package/modules/devtools/src/blitz/fonts.ts +78 -0
- package/modules/devtools/src/blitz/host.ts +110 -34
- package/modules/devtools/src/blitz/panels/console.ts +20 -8
- package/modules/devtools/src/blitz/panels/elements.ts +212 -31
- package/modules/devtools/src/blitz/panels/gpu.ts +4 -2
- package/modules/devtools/src/blitz/panels/performance.ts +26 -14
- package/modules/devtools/src/blitz/panels/snapshot.ts +30 -8
- package/modules/devtools/src/blitz/panels/types.ts +2 -1
- package/modules/devtools/src/blitz/theme.ts +26 -4
- package/modules/html-ui/src/doc-backend.ts +67 -4
- package/modules/html-ui/src/host.ts +11 -3
- package/modules/html-ui/src/jsx-runtime.ts +1 -1
- package/modules/html-ui/src/protocol.ts +1 -1
- package/package.json +2 -2
|
@@ -76,6 +76,19 @@ interface DocState {
|
|
|
76
76
|
gpuTex: { ptr: number | bigint; tex: unknown; w: number; h: number } | null;
|
|
77
77
|
stats: { frames: number; resolveMs: number; paintMs: number; diffMs: number; bytes: number };
|
|
78
78
|
statsLast: number;
|
|
79
|
+
/** smoothWheel (PanelSpec): wheel deltas accumulate here and drain as
|
|
80
|
+
* eased per-tick steps in pump() instead of each event repainting an
|
|
81
|
+
* instant jump. Deltas/positions stay in doc CSS px (scale applied at
|
|
82
|
+
* dispatch); DOM sign convention (+y = scroll down). */
|
|
83
|
+
smoothWheel: boolean;
|
|
84
|
+
wheelRx: number;
|
|
85
|
+
wheelRy: number;
|
|
86
|
+
wheelX: number;
|
|
87
|
+
wheelY: number;
|
|
88
|
+
wheelMods?: string[];
|
|
89
|
+
/** performance.now() of the last step — the ease is dt-based so the curve
|
|
90
|
+
* holds regardless of pump cadence. */
|
|
91
|
+
wheelT: number;
|
|
79
92
|
}
|
|
80
93
|
|
|
81
94
|
// Bound-buffer header (u32 indices) — mirrors BoundBuf layout in lib.rs.
|
|
@@ -211,9 +224,32 @@ export function createDocCore(emit: (m: WorkerToUi) => void, gpuHooks?: DocGpuHo
|
|
|
211
224
|
}
|
|
212
225
|
}
|
|
213
226
|
|
|
227
|
+
// Smooth-wheel ease: fraction of the remainder applied per elapsed ms.
|
|
228
|
+
// τ≈45ms → ~30% per 16ms tick, ~95% drained in ~135ms — snappy but
|
|
229
|
+
// animated. A 1/MAX_TICKS floor bounds any backlog at ~320ms of drain —
|
|
230
|
+
// a fast wheel can't make scroll trail input indefinitely. Dispatching
|
|
231
|
+
// real wheel events keeps Blitz's hit-testing, scroll chaining, scrollbar
|
|
232
|
+
// reveal, and scroll DOM events intact.
|
|
233
|
+
const WHEEL_TAU_MS = 45;
|
|
234
|
+
const WHEEL_MAX_TICKS = 20;
|
|
235
|
+
function stepWheel(s: DocState, now: number): void {
|
|
236
|
+
const dt = Math.min(50, Math.max(1, now - s.wheelT));
|
|
237
|
+
s.wheelT = now;
|
|
238
|
+
const f = Math.max(1 - Math.exp(-dt / WHEEL_TAU_MS), 1 / WHEEL_MAX_TICKS);
|
|
239
|
+
// Snap the tail: a step below ~¾px/axis applies the whole residue instead
|
|
240
|
+
// of asymptoting through invisible sub-pixel repaints.
|
|
241
|
+
const dx = Math.abs(s.wheelRx) * f < 0.75 ? s.wheelRx : s.wheelRx * f;
|
|
242
|
+
const dy = Math.abs(s.wheelRy) * f < 0.75 ? s.wheelRy : s.wheelRy * f;
|
|
243
|
+
s.wheelRx -= dx;
|
|
244
|
+
s.wheelRy -= dy;
|
|
245
|
+
const k = s.scale;
|
|
246
|
+
s.doc.wheel(s.wheelX * k, s.wheelY * k, dx * k, dy * k, s.wheelMods);
|
|
247
|
+
}
|
|
248
|
+
|
|
214
249
|
function pump() {
|
|
215
250
|
const now = performance.now();
|
|
216
251
|
for (const [id, s] of docs.entries()) {
|
|
252
|
+
if (s.smoothWheel && (s.wheelRx !== 0 || s.wheelRy !== 0)) stepWheel(s, now);
|
|
217
253
|
const events = s.doc.pollEvents();
|
|
218
254
|
if (events.length) emit({ type: "events", id, events });
|
|
219
255
|
if (!s.doc.pending()) continue;
|
|
@@ -284,6 +320,8 @@ export function createDocCore(emit: (m: WorkerToUi) => void, gpuHooks?: DocGpuHo
|
|
|
284
320
|
doc, scale: m.scale, cssW: m.cssW, cssH: m.cssH,
|
|
285
321
|
maxFps: m.maxFps ?? 0, lastFrame: -1e9,
|
|
286
322
|
sab: null, sabU32: null, sabDisabled: false, gpuTex: null,
|
|
323
|
+
smoothWheel: m.smoothWheel === true,
|
|
324
|
+
wheelRx: 0, wheelRy: 0, wheelX: 0, wheelY: 0, wheelT: 0,
|
|
287
325
|
stats: freshStats(), statsLast: 0,
|
|
288
326
|
};
|
|
289
327
|
docs.set(m.id, s);
|
|
@@ -295,9 +333,16 @@ export function createDocCore(emit: (m: WorkerToUi) => void, gpuHooks?: DocGpuHo
|
|
|
295
333
|
if (s) s.maxFps = m.maxFps;
|
|
296
334
|
break;
|
|
297
335
|
}
|
|
298
|
-
case "setHtml":
|
|
336
|
+
case "setHtml": {
|
|
299
337
|
if (/float\s*:/.test(m.html)) emit({ type: "error", id: m.id, message: "CSS float hangs Blitz layout — use flex instead" });
|
|
300
|
-
docs.get(m.id)
|
|
338
|
+
const s = docs.get(m.id);
|
|
339
|
+
if (!s) break;
|
|
340
|
+
// Drop any in-flight smooth-wheel drain — its remainder belongs to
|
|
341
|
+
// the document being replaced.
|
|
342
|
+
s.wheelRx = s.wheelRy = 0;
|
|
343
|
+
s.doc.setHtml(m.html);
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
301
346
|
case "resize": {
|
|
302
347
|
const s = docs.get(m.id);
|
|
303
348
|
if (s) {
|
|
@@ -403,9 +448,27 @@ export function createDocCore(emit: (m: WorkerToUi) => void, gpuHooks?: DocGpuHo
|
|
|
403
448
|
const k = s.scale;
|
|
404
449
|
switch (msg.kind) {
|
|
405
450
|
case "move": s.doc.pointerMove(msg.x * k, msg.y * k, msg.mods); break;
|
|
406
|
-
case "down":
|
|
451
|
+
case "down":
|
|
452
|
+
// A press interrupts any in-flight wheel scroll (mirrors
|
|
453
|
+
// Blitz's interrupt_animation semantics for user input).
|
|
454
|
+
s.wheelRx = 0; s.wheelRy = 0;
|
|
455
|
+
s.doc.pointerDown(msg.x * k, msg.y * k, msg.button, msg.mods);
|
|
456
|
+
break;
|
|
407
457
|
case "up": s.doc.pointerUp(msg.x * k, msg.y * k, msg.button, msg.mods); break;
|
|
408
|
-
case "wheel":
|
|
458
|
+
case "wheel":
|
|
459
|
+
if (s.smoothWheel) {
|
|
460
|
+
// A fresh gesture back-dates wheelT so the first pump tick
|
|
461
|
+
// applies a full ~16ms step immediately — no dead frame.
|
|
462
|
+
if (s.wheelRx === 0 && s.wheelRy === 0) s.wheelT = performance.now() - 16;
|
|
463
|
+
s.wheelRx += msg.deltaX;
|
|
464
|
+
s.wheelRy += msg.deltaY;
|
|
465
|
+
s.wheelX = msg.x;
|
|
466
|
+
s.wheelY = msg.y;
|
|
467
|
+
s.wheelMods = msg.mods;
|
|
468
|
+
} else {
|
|
469
|
+
s.doc.wheel(msg.x * k, msg.y * k, msg.deltaX * k, msg.deltaY * k, msg.mods);
|
|
470
|
+
}
|
|
471
|
+
break;
|
|
409
472
|
case "key": s.doc.key(msg.down, msg.key, msg.code, msg.text, msg.mods); break;
|
|
410
473
|
}
|
|
411
474
|
break;
|
|
@@ -10,6 +10,7 @@ import type { OsrDomEvent } from "@downdraft/engine/libraries/blitz-ui/native-os
|
|
|
10
10
|
import type { InputEventControl, RendererInputBus } from "@downdraft/engine/module/renderer-module";
|
|
11
11
|
import { getHostCapabilities, getNativeHost } from "@downdraft/engine/platform/runtime";
|
|
12
12
|
import { createLogger } from "@downdraft/engine/util/logger";
|
|
13
|
+
import { untrackedTimeout } from "@downdraft/engine/util/session-timer";
|
|
13
14
|
import { PanelBlitPass } from "./composite";
|
|
14
15
|
import { createLocalBackend, createWorkerBackend, type DocBackend } from "./doc-backend";
|
|
15
16
|
import type { DocInputMsg, DocMutation, NavNodeInfo, UiPointerMsg, WorkerToUi } from "./protocol";
|
|
@@ -40,6 +41,10 @@ export interface PanelSpec {
|
|
|
40
41
|
zoom?: number;
|
|
41
42
|
/** Raster-rate cap for animating docs (0 = uncapped). Static docs repaint on demand regardless. */
|
|
42
43
|
maxFps?: number;
|
|
44
|
+
/** Ease wheel deltas out at frame cadence instead of applying each detent
|
|
45
|
+
* as an instant jump — scrolling animates smoothly and repaints stay at
|
|
46
|
+
* one per pump tick regardless of input rate. Default false. */
|
|
47
|
+
smoothWheel?: boolean;
|
|
43
48
|
/** Initial markup (or `vdom` rendered beforehand by the caller). */
|
|
44
49
|
html: string;
|
|
45
50
|
/** When false the panel never receives pointer input and `panelAt` skips
|
|
@@ -306,7 +311,7 @@ export class HtmlUiHost {
|
|
|
306
311
|
this.order.push(id);
|
|
307
312
|
// Doc viewport scale = raster px per CSS px = scale * zoom; layout size
|
|
308
313
|
// is rect/zoom CSS px so the raster still covers rect*scale texture px.
|
|
309
|
-
this.send({ type: "create", id, cssW: spec.rect.w / zoom, cssH: spec.docH ?? spec.rect.h / zoom, scale: scale * zoom, html: spec.html, maxFps: spec.maxFps });
|
|
314
|
+
this.send({ type: "create", id, cssW: spec.rect.w / zoom, cssH: spec.docH ?? spec.rect.h / zoom, scale: scale * zoom, html: spec.html, maxFps: spec.maxFps, smoothWheel: spec.smoothWheel });
|
|
310
315
|
// GPU-direct: create the panel texture eagerly so the worker's texBind
|
|
311
316
|
// lands before its first upload — the host knows raster dims at mount.
|
|
312
317
|
if (this.gpuReady) this.bindPanelTex(panel);
|
|
@@ -470,6 +475,9 @@ export class HtmlUiHost {
|
|
|
470
475
|
* `incrementalDom` is false until then, and forever on old cdylibs). */
|
|
471
476
|
get docCaps(): { incrementalDom: boolean } { return this.caps; }
|
|
472
477
|
|
|
478
|
+
/** Which doc backend is live — "worker" (raster off-thread) or "local". */
|
|
479
|
+
get backendKind(): "worker" | "local" { return this.backend.kind; }
|
|
480
|
+
|
|
473
481
|
/** Compositor surface for GameRenderer's end-of-frame UI pass. */
|
|
474
482
|
get compositor(): { hasContent(): boolean; render(pass: GPURenderPassEncoder, w: number, h: number): void } {
|
|
475
483
|
return {
|
|
@@ -511,7 +519,7 @@ export class HtmlUiHost {
|
|
|
511
519
|
this.terminating = true;
|
|
512
520
|
this.send({ type: "gpuDetach" });
|
|
513
521
|
const backend = this.backend;
|
|
514
|
-
|
|
522
|
+
untrackedTimeout(() => {
|
|
515
523
|
if (!this.gpuDetachAcked) backend.dispose();
|
|
516
524
|
this.destroyRetired();
|
|
517
525
|
}, 150);
|
|
@@ -912,7 +920,7 @@ export class HtmlUiHost {
|
|
|
912
920
|
|| (p.postedBindPtr !== null && BigInt(ptr) === p.postedBindPtr));
|
|
913
921
|
if (borrowed) {
|
|
914
922
|
const key = BigInt(ptr);
|
|
915
|
-
const timer =
|
|
923
|
+
const timer = untrackedTimeout(() => {
|
|
916
924
|
if (this.retiredTex.delete(key)) t.destroy();
|
|
917
925
|
}, 1000);
|
|
918
926
|
this.retiredTex.set(key, { tex: t, timer });
|
|
@@ -52,7 +52,7 @@ export interface NavNodeInfo {
|
|
|
52
52
|
|
|
53
53
|
/** Host → backend */
|
|
54
54
|
export type UiToWorker =
|
|
55
|
-
| { type: "create"; id: string; cssW: number; cssH: number; scale: number; html: string; maxFps?: number }
|
|
55
|
+
| { type: "create"; id: string; cssW: number; cssH: number; scale: number; html: string; maxFps?: number; smoothWheel?: boolean }
|
|
56
56
|
| { type: "fps"; id: string; maxFps: number }
|
|
57
57
|
| { type: "setHtml"; id: string; html: string }
|
|
58
58
|
| { type: "resize"; id: string; cssW: number; cssH: number; scale: number }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@downdraft/engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/knackstedt/downdraft.git",
|
|
@@ -865,7 +865,7 @@
|
|
|
865
865
|
"zustand": "^5.0.2"
|
|
866
866
|
},
|
|
867
867
|
"peerDependencies": {
|
|
868
|
-
"@downdraft/platform-native": "^0.
|
|
868
|
+
"@downdraft/platform-native": "^0.3.0"
|
|
869
869
|
},
|
|
870
870
|
"peerDependenciesMeta": {
|
|
871
871
|
"@downdraft/platform-native": {
|