@graview/render 0.0.0-stage → 0.1.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.
Files changed (47) hide show
  1. package/LICENSE +96 -0
  2. package/README.md +43 -2
  3. package/dist/gpu.d.ts +6 -0
  4. package/dist/gpu.d.ts.map +1 -0
  5. package/dist/gpu.js +23 -0
  6. package/dist/gpu.js.map +1 -0
  7. package/dist/index.d.ts +12 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +31 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/interaction/pointer-router.d.ts +94 -0
  12. package/dist/interaction/pointer-router.d.ts.map +1 -0
  13. package/dist/interaction/pointer-router.js +148 -0
  14. package/dist/interaction/pointer-router.js.map +1 -0
  15. package/dist/platform/html-in-canvas.d.ts +100 -0
  16. package/dist/platform/html-in-canvas.d.ts.map +1 -0
  17. package/dist/platform/html-in-canvas.js +172 -0
  18. package/dist/platform/html-in-canvas.js.map +1 -0
  19. package/dist/platform/matrix.d.ts +53 -0
  20. package/dist/platform/matrix.d.ts.map +1 -0
  21. package/dist/platform/matrix.js +61 -0
  22. package/dist/platform/matrix.js.map +1 -0
  23. package/dist/scene/compositor.d.ts +112 -0
  24. package/dist/scene/compositor.d.ts.map +1 -0
  25. package/dist/scene/compositor.js +340 -0
  26. package/dist/scene/compositor.js.map +1 -0
  27. package/dist/scene/compositor.wgsl.d.ts +15 -0
  28. package/dist/scene/compositor.wgsl.d.ts.map +1 -0
  29. package/dist/scene/compositor.wgsl.js +106 -0
  30. package/dist/scene/compositor.wgsl.js.map +1 -0
  31. package/dist/scene/connectors.d.ts +60 -0
  32. package/dist/scene/connectors.d.ts.map +1 -0
  33. package/dist/scene/connectors.js +95 -0
  34. package/dist/scene/connectors.js.map +1 -0
  35. package/dist/scene/frame-plan.d.ts +83 -0
  36. package/dist/scene/frame-plan.d.ts.map +1 -0
  37. package/dist/scene/frame-plan.js +119 -0
  38. package/dist/scene/frame-plan.js.map +1 -0
  39. package/dist/scene/from-layout.d.ts +14 -0
  40. package/dist/scene/from-layout.d.ts.map +1 -0
  41. package/dist/scene/from-layout.js +35 -0
  42. package/dist/scene/from-layout.js.map +1 -0
  43. package/dist/scene/plane.d.ts +68 -0
  44. package/dist/scene/plane.d.ts.map +1 -0
  45. package/dist/scene/plane.js +94 -0
  46. package/dist/scene/plane.js.map +1 -0
  47. package/package.json +64 -3
@@ -0,0 +1,172 @@
1
+ /// <reference types="@webgpu/types" />
2
+ //
3
+ // The WebGPU globals are part of this file's PUBLIC declarations, so the
4
+ // reference has to live HERE rather than on the package entry: TypeScript
5
+ // drops a type reference from a `.d.ts` that does not itself name one of its
6
+ // types, so a reference on `index.ts` was emitted nowhere and an installed
7
+ // consumer got "cannot find name GPUDevice" from a file they cannot change.
8
+ // Found by typechecking a scratch project against the packed tarballs.
9
+ //
10
+ // It also has to be the ONLY route in: listing `@webgpu/types` under
11
+ // `compilerOptions.types` makes the globals ambient for this build, at which
12
+ // point TypeScript considers the reference satisfied and drops it from the
13
+ // emit. The build sees no difference; a stranger does.
14
+ /**
15
+ * THE platform seam. Every call into the HTML-in-Canvas API passes through
16
+ * this module and nowhere else.
17
+ *
18
+ * The API is mid-origin-trial and its naming is still settling — the WICG
19
+ * README calls the capture entry point `drawElementImageToTexture` in one
20
+ * place and `copyElementImageToTexture` in another — so the whole surface is
21
+ * resolved once, at runtime, behind names of our own. When the spec settles,
22
+ * exactly one file changes.
23
+ *
24
+ * Verified against Chrome Canary 154.0.8032.0 with
25
+ * `--enable-blink-features=CanvasDrawElement`. What that build actually
26
+ * exposes, and the exact call shapes, are recorded in
27
+ * `docs/platform-findings.md`; the shapes below are what it accepts, not what
28
+ * the README suggests.
29
+ */
30
+ import { IDENTITY, isAffine, perspectiveProbeMatrix, planeTransform, toDOMMatrix, } from "./matrix.js";
31
+ export { IDENTITY, isAffine, perspectiveProbeMatrix, planeTransform, toDOMMatrix };
32
+ const CAPTURE_METHOD_NAMES = [
33
+ "drawElementImageToTexture",
34
+ "copyElementImageToTexture",
35
+ ];
36
+ function scope() {
37
+ return typeof globalThis === "undefined" ? undefined : globalThis;
38
+ }
39
+ /**
40
+ * Resolves what this browser can actually do. Called once; everything else in
41
+ * the renderer branches on the result rather than sniffing again.
42
+ */
43
+ export function detectCapabilities(queue, canvas) {
44
+ const notes = [];
45
+ const g = scope();
46
+ const webgpu = Boolean(g?.navigator && "gpu" in g.navigator);
47
+ if (!webgpu)
48
+ notes.push("navigator.gpu is absent — WebGPU is unavailable.");
49
+ const queueProto = queue ??
50
+ (g?.GPUQueue
51
+ ?.prototype ??
52
+ undefined);
53
+ let captureMethod = null;
54
+ if (queueProto) {
55
+ for (const name of CAPTURE_METHOD_NAMES) {
56
+ if (typeof queueProto[name] === "function") {
57
+ captureMethod = name;
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ if (!captureMethod) {
63
+ notes.push("No element-capture method on GPUQueue. Run Chromium 147+ with " +
64
+ "--enable-blink-features=CanvasDrawElement.");
65
+ }
66
+ const canvasProto = canvas ??
67
+ (g
68
+ ?.HTMLCanvasElement?.prototype ??
69
+ undefined);
70
+ const geometrySync = typeof canvasProto?.updateElementGeometry === "function";
71
+ if (!geometrySync) {
72
+ notes.push("canvas.updateElementGeometry is absent — geometry cannot be reported.");
73
+ }
74
+ const paintEvents = typeof canvasProto?.requestPaint === "function";
75
+ if (!paintEvents) {
76
+ notes.push("canvas.requestPaint is absent — there is no capture-safe moment to hook.");
77
+ }
78
+ let layoutSubtree = false;
79
+ if (typeof document !== "undefined") {
80
+ const probe = document.createElement("canvas");
81
+ layoutSubtree = "layoutSubtree" in probe;
82
+ }
83
+ return {
84
+ available: captureMethod !== null,
85
+ captureMethod,
86
+ geometrySync,
87
+ hitTestFollowsGeometry: "unknown",
88
+ layoutSubtree,
89
+ paintEvents,
90
+ webgpu,
91
+ usable: webgpu && captureMethod !== null,
92
+ notes,
93
+ };
94
+ }
95
+ export class PlatformUnavailableError extends Error {
96
+ capabilities;
97
+ constructor(capabilities) {
98
+ super(`HTML-in-Canvas is unavailable:\n ${capabilities.notes.join("\n ")}`);
99
+ this.capabilities = capabilities;
100
+ this.name = "PlatformUnavailableError";
101
+ }
102
+ }
103
+ /**
104
+ * Captures a DOM element (or a previously taken paint record) into an
105
+ * existing GPU texture.
106
+ *
107
+ * Two preconditions the errors do not make obvious:
108
+ * - the element must be a descendant of a `<canvas layoutsubtree>`, and
109
+ * - that canvas must have a CONFIGURED WebGPU context of its own, or the call
110
+ * fails with "containing canvas does not have a rendering context".
111
+ *
112
+ * The texture is written in place, so the caller keeps ownership and no copy
113
+ * happens on our side.
114
+ */
115
+ export function captureElement(queue, source, texture) {
116
+ const q = queue;
117
+ for (const name of CAPTURE_METHOD_NAMES) {
118
+ const method = q[name];
119
+ if (typeof method === "function") {
120
+ method.call(q, { source }, { destination: { texture } });
121
+ return;
122
+ }
123
+ }
124
+ throw new PlatformUnavailableError(detectCapabilities(queue));
125
+ }
126
+ /**
127
+ * Takes a cached paint record for an element. Only valid inside a `paint`
128
+ * event — outside one the browser has no paint record and throws
129
+ * `InvalidStateError`.
130
+ */
131
+ export function captureElementImage(canvas, element) {
132
+ const target = canvas;
133
+ if (typeof target.captureElementImage !== "function") {
134
+ throw new PlatformUnavailableError(detectCapabilities(undefined, canvas));
135
+ }
136
+ return target.captureElementImage(element);
137
+ }
138
+ /**
139
+ * Tells the browser where an element was actually drawn.
140
+ *
141
+ * The intent of the spec is that hit-testing, focus order, screen readers and
142
+ * find-in-page then resolve against the drawn pixels. In Chromium 154 the
143
+ * call is accepted and has no observable effect on hit-testing — see
144
+ * `docs/platform-findings.md`. Call it anyway (it costs nothing and will
145
+ * start working), and route pointers through `PointerRouter` meanwhile.
146
+ */
147
+ export function updateElementGeometry(canvas, source, update) {
148
+ const target = canvas;
149
+ if (typeof target.updateElementGeometry !== "function") {
150
+ throw new PlatformUnavailableError(detectCapabilities(undefined, canvas));
151
+ }
152
+ target.updateElementGeometry(source, update);
153
+ }
154
+ /** Drops a reported geometry, returning the element to its layout position. */
155
+ export function clearElementGeometry(canvas, source) {
156
+ canvas.clearElementGeometry?.(source);
157
+ }
158
+ /** Asks for a `paint` event — the moment at which capture is legal. */
159
+ export function requestPaint(canvas) {
160
+ canvas.requestPaint?.();
161
+ }
162
+ /** Marks a canvas as owning its descendants' layout. */
163
+ export function setLayoutSubtree(canvas, on = true) {
164
+ const target = canvas;
165
+ if ("layoutSubtree" in target)
166
+ target.layoutSubtree = on;
167
+ else if (on)
168
+ target.setAttribute("layoutsubtree", "");
169
+ else
170
+ target.removeAttribute("layoutsubtree");
171
+ }
172
+ //# sourceMappingURL=html-in-canvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-in-canvas.js","sourceRoot":"","sources":["../../src/platform/html-in-canvas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Affine 4x4 matrices, and the plane transform built from one.
3
+ *
4
+ * Split out of the platform seam because it is PURE: no DOM, no WebGPU, no
5
+ * ambient globals. That matters for more than tidiness — the platform module's
6
+ * declarations name `GPUQueue`, which is an ambient global from
7
+ * `@webgpu/types`, so anything re-exported from there drags that requirement
8
+ * onto every consumer. The geometry every app uses should not.
9
+ *
10
+ * Affine is not a style choice here. The capture pipeline composites textures
11
+ * with a per-plane transform, and a perspective divide would mean resampling
12
+ * each captured view every frame; `isAffine` is the guard that keeps that
13
+ * true, and it is checked in tests on both renderer paths.
14
+ */
15
+ export type Matrix4 = readonly [
16
+ number,
17
+ number,
18
+ number,
19
+ number,
20
+ number,
21
+ number,
22
+ number,
23
+ number,
24
+ number,
25
+ number,
26
+ number,
27
+ number,
28
+ number,
29
+ number,
30
+ number,
31
+ number
32
+ ];
33
+ /** An opaque cached paint record for one element, from `captureElementImage`. */
34
+ /**
35
+ * Whether a matrix is affine — no perspective row.
36
+ *
37
+ * The plane model is designed so that everything it emits passes this test:
38
+ * depth is per-plane uniform scale, blur and shadow, never per-element
39
+ * foreshortening. That keeps the model correct whichever way the platform
40
+ * settles the perspective question.
41
+ */
42
+ export declare function isAffine(matrix: Matrix4): boolean;
43
+ /** Column-major 4x4 identity. */
44
+ export declare const IDENTITY: Matrix4;
45
+ /**
46
+ * The affine transform a plane contributes: uniform scale about the canvas
47
+ * origin plus a translation. Deliberately nothing else.
48
+ */
49
+ export declare function planeTransform(scale: number, translateX: number, translateY: number): Matrix4;
50
+ /** A perspective matrix, used only to ask the browser whether it takes one. */
51
+ export declare function perspectiveProbeMatrix(depth?: number): Matrix4;
52
+ export declare function toDOMMatrix(matrix: Matrix4 | DOMMatrix): DOMMatrix;
53
+ //# sourceMappingURL=matrix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matrix.d.ts","sourceRoot":"","sources":["../../src/platform/matrix.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,OAAO,GAAG,SAAS;IAC7B,MAAM;IAAE,MAAM;IAAE,MAAM;IAAE,MAAM;IAC9B,MAAM;IAAE,MAAM;IAAE,MAAM;IAAE,MAAM;IAC9B,MAAM;IAAE,MAAM;IAAE,MAAM;IAAE,MAAM;IAC9B,MAAM;IAAE,MAAM;IAAE,MAAM;IAAE,MAAM;CAC/B,CAAC;AAEF,iFAAiF;AAEjF;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAEjD;AAED,iCAAiC;AACjC,eAAO,MAAM,QAAQ,EAAE,OAKtB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAOT;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,KAAK,SAAM,GAAG,OAAO,CAO3D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAKlE"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Affine 4x4 matrices, and the plane transform built from one.
3
+ *
4
+ * Split out of the platform seam because it is PURE: no DOM, no WebGPU, no
5
+ * ambient globals. That matters for more than tidiness — the platform module's
6
+ * declarations name `GPUQueue`, which is an ambient global from
7
+ * `@webgpu/types`, so anything re-exported from there drags that requirement
8
+ * onto every consumer. The geometry every app uses should not.
9
+ *
10
+ * Affine is not a style choice here. The capture pipeline composites textures
11
+ * with a per-plane transform, and a perspective divide would mean resampling
12
+ * each captured view every frame; `isAffine` is the guard that keeps that
13
+ * true, and it is checked in tests on both renderer paths.
14
+ */
15
+ /** An opaque cached paint record for one element, from `captureElementImage`. */
16
+ /**
17
+ * Whether a matrix is affine — no perspective row.
18
+ *
19
+ * The plane model is designed so that everything it emits passes this test:
20
+ * depth is per-plane uniform scale, blur and shadow, never per-element
21
+ * foreshortening. That keeps the model correct whichever way the platform
22
+ * settles the perspective question.
23
+ */
24
+ export function isAffine(matrix) {
25
+ return matrix[3] === 0 && matrix[7] === 0 && matrix[11] === 0 && matrix[15] === 1;
26
+ }
27
+ /** Column-major 4x4 identity. */
28
+ export const IDENTITY = [
29
+ 1, 0, 0, 0,
30
+ 0, 1, 0, 0,
31
+ 0, 0, 1, 0,
32
+ 0, 0, 0, 1,
33
+ ];
34
+ /**
35
+ * The affine transform a plane contributes: uniform scale about the canvas
36
+ * origin plus a translation. Deliberately nothing else.
37
+ */
38
+ export function planeTransform(scale, translateX, translateY) {
39
+ return [
40
+ scale, 0, 0, 0,
41
+ 0, scale, 0, 0,
42
+ 0, 0, 1, 0,
43
+ translateX, translateY, 0, 1,
44
+ ];
45
+ }
46
+ /** A perspective matrix, used only to ask the browser whether it takes one. */
47
+ export function perspectiveProbeMatrix(depth = 800) {
48
+ return [
49
+ 1, 0, 0, 0,
50
+ 0, 1, 0, 0,
51
+ 0, 0, 1, -1 / depth,
52
+ 0, 0, 0, 1,
53
+ ];
54
+ }
55
+ export function toDOMMatrix(matrix) {
56
+ if (typeof DOMMatrix === "undefined") {
57
+ throw new Error("DOMMatrix is unavailable outside a browser");
58
+ }
59
+ return matrix instanceof DOMMatrix ? matrix : new DOMMatrix([...matrix]);
60
+ }
61
+ //# sourceMappingURL=matrix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matrix.js","sourceRoot":"","sources":["../../src/platform/matrix.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,iFAAiF;AAEjF;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAe;IACtC,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AACpF,CAAC;AAED,iCAAiC;AACjC,MAAM,CAAC,MAAM,QAAQ,GAAY;IAC/B,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACV,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACV,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACV,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;CACX,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,UAAkB,EAClB,UAAkB;IAElB,OAAO;QACL,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QACd,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACd,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QACV,UAAU,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,sBAAsB,CAAC,KAAK,GAAG,GAAG;IAChD,OAAO;QACL,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QACV,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QACV,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;QACnB,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAA2B;IACrD,IAAI,OAAO,SAAS,KAAK,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,MAAM,YAAY,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,112 @@
1
+ import { type Placement } from "../interaction/pointer-router.js";
2
+ import { type PlatformCapabilities } from "../platform/html-in-canvas.js";
3
+ import type { ConnectorStyle } from "./connectors.js";
4
+ import { type FramePlan, type PlannedConnector, type PlannedView, type ViewDraw } from "./frame-plan.js";
5
+ /** A view in the scene: its DOM subtree, plus everything the plan needs. */
6
+ export interface SceneView extends PlannedView {
7
+ /**
8
+ * The element captured for this view. It MUST be an immediate child of the
9
+ * scene canvas — the platform rejects anything deeper. Its own descendants
10
+ * are captured with it.
11
+ */
12
+ readonly element: HTMLElement;
13
+ }
14
+ /**
15
+ * The minimum of a WebGPU device this module uses, said structurally: a
16
+ * device from `navigator.gpu`, from `vgpu`, `vgpu/node` or `vgpu/mock` all
17
+ * fit, and this package depends on none of them.
18
+ */
19
+ export interface VgpuLike {
20
+ readonly device: {
21
+ readonly gpu: GPUDevice;
22
+ };
23
+ dispose?(): void;
24
+ }
25
+ export interface SurfaceLike {
26
+ readonly context: GPUCanvasContext;
27
+ }
28
+ export interface CompositorDeps {
29
+ readonly gpu: VgpuLike;
30
+ readonly surface: SurfaceLike;
31
+ }
32
+ export interface CompositorOptions {
33
+ /** The ground colour receded planes drift toward. Defaults to a warm off-white. */
34
+ readonly ground?: readonly [number, number, number];
35
+ /** Stand the pointer router down once a browser redirects hit-testing itself. */
36
+ readonly platformHandlesHitTesting?: boolean;
37
+ readonly connectorOverrides?: Readonly<Record<string, Partial<ConnectorStyle>>>;
38
+ }
39
+ /**
40
+ * Captures views into GPU textures and composites them as quads at plane
41
+ * depth, then reports each drawn position back to the browser.
42
+ *
43
+ * The frame is decided by `planFrame` — which fidelity captures, what order
44
+ * things draw in, where each view lands — and this class only submits it.
45
+ * Keeping the decisions out of here is what lets them be tested in CI with
46
+ * no GPU and no DOM.
47
+ */
48
+ export declare class Compositor {
49
+ readonly canvas: HTMLCanvasElement;
50
+ private readonly deps;
51
+ private readonly options;
52
+ private readonly views;
53
+ private readonly resources;
54
+ private readonly capturedAt;
55
+ private readonly router;
56
+ private pipeline;
57
+ private sampler;
58
+ private frame;
59
+ private detachRouter;
60
+ private connectors;
61
+ private lastPlan;
62
+ private lastPlacements;
63
+ readonly capabilities: PlatformCapabilities;
64
+ constructor(canvas: HTMLCanvasElement, deps: CompositorDeps, options?: CompositorOptions);
65
+ attach(): () => void;
66
+ detach(): void;
67
+ /**
68
+ * Brings the scene in line with a new set of views, keeping the GPU
69
+ * resources of everything that survived.
70
+ *
71
+ * Removing and re-adding every view on each edit destroys and reallocates
72
+ * every texture, which is both wasteful and — at this scene's size — enough
73
+ * to bring the GPU process down. Reconciling touches only what changed.
74
+ */
75
+ reconcile(views: readonly SceneView[]): void;
76
+ /** Whether this view's cached texture still reflects what it looks like. */
77
+ private capturedAtIsFresh;
78
+ add(view: SceneView): void;
79
+ remove(id: string): void;
80
+ /** Replaces the connector set, e.g. after a layout change. */
81
+ setConnectors(connectors: readonly PlannedConnector[]): void;
82
+ /** Marks a view's texture stale, so the next frame recaptures it. */
83
+ invalidate(id: string): void;
84
+ all(): SceneView[];
85
+ /** Last frame's plan. Measurement harnesses and tests only. */
86
+ plan(): FramePlan | null;
87
+ /** Where each view was drawn last frame, with the element it came from. */
88
+ placements(): readonly Placement[];
89
+ /** Raw device handle. Measurement harnesses only. */
90
+ deviceForProbe(): GPUDevice;
91
+ /** Asks the browser for a `paint` event — the only moment capture is legal. */
92
+ scheduleFrame(): void;
93
+ /**
94
+ * One frame: capture what is stale, draw every view back to front, and tell
95
+ * the browser where each one landed.
96
+ *
97
+ * Call this from a `paint` listener. Outside one the browser has no paint
98
+ * record and capture throws.
99
+ */
100
+ render(): FramePlan;
101
+ private groundColor;
102
+ private ensurePipeline;
103
+ private ensureResources;
104
+ private ensureBindGroup;
105
+ dispose(): void;
106
+ }
107
+ /**
108
+ * The uniform layout the compositing shader reads, packed as data so a test
109
+ * can assert on it with no GPU present.
110
+ */
111
+ export declare function packUniform(draw: ViewDraw, canvasWidth: number, canvasHeight: number, ground: readonly [number, number, number]): Float32Array<ArrayBuffer>;
112
+ //# sourceMappingURL=compositor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compositor.d.ts","sourceRoot":"","sources":["../../src/scene/compositor.ts"],"names":[],"mappings":"AAcA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,kCAAkC,CAAC;AACjF,OAAO,EAOL,KAAK,oBAAoB,EAC1B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,iBAAiB,CAAC;AAEzB,4EAA4E;AAC5E,MAAM,WAAW,SAAU,SAAQ,WAAW;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC;IAC7C,OAAO,CAAC,IAAI,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpD,iFAAiF;IACjF,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAC7C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;CACjF;AAYD;;;;;;;;GAQG;AACH,qBAAa,UAAU;IAgBnB,QAAQ,CAAC,MAAM,EAAE,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAjB1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,cAAc,CAA4B;IAElD,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;gBAGjC,MAAM,EAAE,iBAAiB,EACjB,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE,iBAAsB;IAWlD,MAAM,IAAI,MAAM,IAAI;IAKpB,MAAM,IAAI,IAAI;IAKd;;;;;;;OAOG;IACH,SAAS,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,IAAI;IA4B5C,4EAA4E;IAC5E,OAAO,CAAC,iBAAiB;IAIzB,GAAG,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAa1B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IASxB,8DAA8D;IAC9D,aAAa,CAAC,UAAU,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI;IAI5D,qEAAqE;IACrE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK5B,GAAG,IAAI,SAAS,EAAE;IAIlB,+DAA+D;IAC/D,IAAI,IAAI,SAAS,GAAG,IAAI;IAIxB,2EAA2E;IAC3E,UAAU,IAAI,SAAS,SAAS,EAAE;IAIlC,qDAAqD;IACrD,cAAc,IAAI,SAAS;IAI3B,+EAA+E;IAC/E,aAAa,IAAI,IAAI;IAIrB;;;;;;OAMG;IACH,MAAM,IAAI,SAAS;IA+FnB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,eAAe;IAsCvB,OAAO,CAAC,eAAe;IAmBvB,OAAO,IAAI,IAAI;CAIhB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,QAAQ,EACd,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GACxC,YAAY,CAAC,WAAW,CAAC,CAO3B"}