@adobe/ecs-gpu 0.0.1 → 0.0.2
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/dist/index.js +45 -45
- package/dist/index.js.map +1 -1
- package/dist/types/guide/01-targets.d.ts +1 -0
- package/dist/types/guide/02-frames.d.ts +1 -0
- package/package.json +10 -3
- package/src/guide/01-targets.md +13 -0
- package/src/guide/01-targets.out +5 -0
- package/src/guide/01-targets.ts +40 -0
- package/src/guide/02-frames.md +15 -0
- package/src/guide/02-frames.out +2 -0
- package/src/guide/02-frames.ts +33 -0
- package/src/guide/README.md +7 -0
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ var __exportAll = (all, no_symbols) => {
|
|
|
17
17
|
* with the device, so a device a world replaced, or one that was lost, holds nothing here. Keys are compared by
|
|
18
18
|
* `keyOf`, by default their JSON.
|
|
19
19
|
*/
|
|
20
|
-
|
|
20
|
+
const perDevice = (create, keyOf = (key) => JSON.stringify(key)) => {
|
|
21
21
|
const devices = /* @__PURE__ */ new WeakMap();
|
|
22
22
|
return (device, key) => {
|
|
23
23
|
let made = devices.get(device);
|
|
@@ -42,7 +42,7 @@ var public_exports = /* @__PURE__ */ __exportAll({ perDevice: () => perDevice })
|
|
|
42
42
|
* A device on this thread, or null where there's no WebGPU, no adapter for `options`, or the adapter refused the
|
|
43
43
|
* device. Call it on the thread the world runs on: a device can't move between threads.
|
|
44
44
|
*/
|
|
45
|
-
|
|
45
|
+
const request = async (options = {}) => {
|
|
46
46
|
const { requiredFeatures, requiredLimits, ...adapterOptions } = options;
|
|
47
47
|
const adapter = await globalThis.navigator?.gpu?.requestAdapter(adapterOptions);
|
|
48
48
|
if (adapter === null || adapter === void 0) return null;
|
|
@@ -56,7 +56,7 @@ var request = async (options = {}) => {
|
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
/** Sets the world's `gpuDevice`. */
|
|
59
|
-
|
|
59
|
+
const set = System.create({}, ({ resources }, input) => {
|
|
60
60
|
resources[gpuDevice] = input.device;
|
|
61
61
|
}, {
|
|
62
62
|
"type": "object",
|
|
@@ -67,7 +67,7 @@ var set = System.create({}, ({ resources }, input) => {
|
|
|
67
67
|
* once the first request settled, to whether it gave the world a device, and a function that stops keeping it. Call it
|
|
68
68
|
* on the world's thread.
|
|
69
69
|
*/
|
|
70
|
-
|
|
70
|
+
const keep = async (world, options = {}) => {
|
|
71
71
|
let stopped = false;
|
|
72
72
|
const supply = async () => {
|
|
73
73
|
const device = await request(options);
|
|
@@ -94,7 +94,7 @@ var public_exports$1 = /* @__PURE__ */ __exportAll({
|
|
|
94
94
|
});
|
|
95
95
|
//#endregion
|
|
96
96
|
//#region src/target/target.ts
|
|
97
|
-
|
|
97
|
+
const Options$1 = { default: {
|
|
98
98
|
format: null,
|
|
99
99
|
sampleCount: 1,
|
|
100
100
|
depthFormat: "depth24plus",
|
|
@@ -106,9 +106,9 @@ var Options$1 = { default: {
|
|
|
106
106
|
]
|
|
107
107
|
} };
|
|
108
108
|
/** An entity with these is a render target: what its textures are, and their size in pixels. */
|
|
109
|
-
|
|
109
|
+
const options$1 = Symbol("Target.options");
|
|
110
110
|
declare$$2(options$1, "component", { default: Options$1.default });
|
|
111
|
-
|
|
111
|
+
const size = Symbol("Target.size");
|
|
112
112
|
declare$$2(size, "component", { type: {
|
|
113
113
|
"type": "array",
|
|
114
114
|
"items": {
|
|
@@ -120,15 +120,15 @@ declare$$2(size, "component", { type: {
|
|
|
120
120
|
"maxItems": 2
|
|
121
121
|
} });
|
|
122
122
|
/** Each render target's textures on the world's device, by its entity: null until targets are first updated. */
|
|
123
|
-
|
|
123
|
+
const states$2 = Symbol("Target.states");
|
|
124
124
|
declare$$2(states$2, "resource", {});
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
const sameOptions$1 = (a, b) => a.format === b.format && a.sampleCount === b.sampleCount && a.depthFormat === b.depthFormat && (a.clear === b.clear || a.clear !== null && b.clear !== null && a.clear.every((value, index) => value === b.clear?.[index]));
|
|
126
|
+
const destroyTextures = (state) => {
|
|
127
127
|
state.color.destroy();
|
|
128
128
|
state.multisampled?.destroy();
|
|
129
129
|
state.depth?.destroy();
|
|
130
130
|
};
|
|
131
|
-
|
|
131
|
+
const created = (device, entity, declared, [width, height]) => {
|
|
132
132
|
const format = declared.format ?? navigator.gpu.getPreferredCanvasFormat();
|
|
133
133
|
const extent = [width, height];
|
|
134
134
|
const color = device.createTexture({
|
|
@@ -166,7 +166,7 @@ var created = (device, entity, declared, [width, height]) => {
|
|
|
166
166
|
* Each render target's textures on `device`, made again where its options, its size or the device changed, destroying
|
|
167
167
|
* those they replace; with no device, none. Gives `previous` itself when nothing changed.
|
|
168
168
|
*/
|
|
169
|
-
|
|
169
|
+
const updated$2 = (device, previous, targets) => {
|
|
170
170
|
const held = previous ?? /* @__PURE__ */ new Map();
|
|
171
171
|
let next = null;
|
|
172
172
|
for (let i = 0; i < targets.length; i++) {
|
|
@@ -183,7 +183,7 @@ var updated$2 = (device, previous, targets) => {
|
|
|
183
183
|
return next ?? held;
|
|
184
184
|
};
|
|
185
185
|
/** Records clearing each target that declares a clear color: its color to that color, and its depth to 1. */
|
|
186
|
-
|
|
186
|
+
const recordClears = (encoder, targets) => {
|
|
187
187
|
for (const target of targets.values()) {
|
|
188
188
|
const color = target.options.clear;
|
|
189
189
|
if (color === null) continue;
|
|
@@ -212,7 +212,7 @@ var recordClears = (encoder, targets) => {
|
|
|
212
212
|
}
|
|
213
213
|
};
|
|
214
214
|
/** Destroys a render target's textures when it stops being one. */
|
|
215
|
-
|
|
215
|
+
const release$2 = Finalizer.create({ components: { with: [options$1, size] } }, (target, { resources }) => {
|
|
216
216
|
const current = resources[states$2];
|
|
217
217
|
const state = current?.get(target.entity);
|
|
218
218
|
if (current === null || state === void 0) return;
|
|
@@ -222,7 +222,7 @@ var release$2 = Finalizer.create({ components: { with: [options$1, size] } }, (t
|
|
|
222
222
|
resources[states$2] = next;
|
|
223
223
|
});
|
|
224
224
|
/** Sets a render target's size in pixels, at least one by one. */
|
|
225
|
-
|
|
225
|
+
const resize = System.create({
|
|
226
226
|
components: { with: [size] },
|
|
227
227
|
target: "target"
|
|
228
228
|
}, (row, _context, input) => {
|
|
@@ -256,7 +256,7 @@ var public_exports$4 = /* @__PURE__ */ __exportAll({
|
|
|
256
256
|
});
|
|
257
257
|
//#endregion
|
|
258
258
|
//#region src/surface/surface.ts
|
|
259
|
-
|
|
259
|
+
const Options = { default: {
|
|
260
260
|
alphaMode: "opaque",
|
|
261
261
|
colorSpace: "srgb",
|
|
262
262
|
toneMapping: "standard"
|
|
@@ -265,18 +265,18 @@ var Options = { default: {
|
|
|
265
265
|
* A render target with these presents to a canvas: the canvas, on the world's thread, and how it presents. The
|
|
266
266
|
* canvas's size follows the target's.
|
|
267
267
|
*/
|
|
268
|
-
|
|
268
|
+
const canvas = Symbol("Surface.canvas");
|
|
269
269
|
declare$$1(canvas, "component", { transfer: true });
|
|
270
|
-
|
|
270
|
+
const options = Symbol("Surface.options");
|
|
271
271
|
declare$$1(options, "component", { default: Options.default });
|
|
272
272
|
/** Each surface's configured canvas, by its entity: null until surfaces are first updated. */
|
|
273
|
-
|
|
273
|
+
const states$1 = Symbol("Surface.states");
|
|
274
274
|
declare$$1(states$1, "resource", {});
|
|
275
275
|
/**
|
|
276
276
|
* A surface presenting to `canvas`, moved to the world's thread, of `width` by `height` pixels: a canvas's
|
|
277
277
|
* `transferControlToOffscreen()`, or an `OffscreenCanvas` of its own. Resolves to its entity.
|
|
278
278
|
*/
|
|
279
|
-
|
|
279
|
+
const attach = System.create({}, ({ commands }, input) => commands.spawn([
|
|
280
280
|
options$1,
|
|
281
281
|
size,
|
|
282
282
|
canvas,
|
|
@@ -324,12 +324,12 @@ var attach = System.create({}, ({ commands }, input) => commands.spawn([
|
|
|
324
324
|
"height"
|
|
325
325
|
]
|
|
326
326
|
});
|
|
327
|
-
|
|
327
|
+
const sameOptions = (a, b) => a.alphaMode === b.alphaMode && a.colorSpace === b.colorSpace && a.toneMapping === b.toneMapping;
|
|
328
328
|
/**
|
|
329
329
|
* Each surface's canvas sized to its target and configured for `device` in its target's format, again where either
|
|
330
330
|
* changed; with no device, or no target state, unconfigured. Gives `previous` itself when nothing changed.
|
|
331
331
|
*/
|
|
332
|
-
|
|
332
|
+
const updated$1 = (device, targets, previous, surfaces) => {
|
|
333
333
|
const held = previous ?? /* @__PURE__ */ new Map();
|
|
334
334
|
let next = null;
|
|
335
335
|
for (let i = 0; i < surfaces.length; i++) {
|
|
@@ -372,7 +372,7 @@ var updated$1 = (device, targets, previous, surfaces) => {
|
|
|
372
372
|
return next ?? held;
|
|
373
373
|
};
|
|
374
374
|
/** Unconfigures a surface's canvas when it stops being one. */
|
|
375
|
-
|
|
375
|
+
const release$1 = Finalizer.create({ components: { with: [canvas] } }, (surface, { resources }) => {
|
|
376
376
|
const current = resources[states$1];
|
|
377
377
|
const state = current?.get(surface.entity);
|
|
378
378
|
if (current === null || state === void 0) return;
|
|
@@ -382,7 +382,7 @@ var release$1 = Finalizer.create({ components: { with: [canvas] } }, (surface, {
|
|
|
382
382
|
resources[states$1] = next;
|
|
383
383
|
});
|
|
384
384
|
/** A canvas's size in device pixels, from what a `ResizeObserver` saw of it. */
|
|
385
|
-
|
|
385
|
+
const pixelsOf = (entry) => {
|
|
386
386
|
const [device] = entry.devicePixelContentBoxSize ?? [];
|
|
387
387
|
if (device !== void 0) return [device.inlineSize, device.blockSize];
|
|
388
388
|
const [box] = entry.contentBoxSize;
|
|
@@ -393,7 +393,7 @@ var pixelsOf = (entry) => {
|
|
|
393
393
|
* Keeps a surface's size the size of `element` on the page, in device pixels, on the thread the page is on: the world
|
|
394
394
|
* may be here or on a worker that joined it. Returns a function that stops.
|
|
395
395
|
*/
|
|
396
|
-
|
|
396
|
+
const observe = (element, world, surface) => {
|
|
397
397
|
const observer = new ResizeObserver((entries) => {
|
|
398
398
|
const entry = entries.at(-1);
|
|
399
399
|
if (entry === void 0) return;
|
|
@@ -423,7 +423,7 @@ function declare$$1(key, kind, declaration) {
|
|
|
423
423
|
* An entity with these is a view: the render target it draws into, which owns it; its rectangle in that target as
|
|
424
424
|
* fractions of its size (`x`, `y`, `width`, `height`); and the matrix taking its scene to clip space.
|
|
425
425
|
*/
|
|
426
|
-
|
|
426
|
+
const target = Symbol("View.target");
|
|
427
427
|
declare$(target, "component", {
|
|
428
428
|
type: {
|
|
429
429
|
"type": "integer",
|
|
@@ -431,7 +431,7 @@ declare$(target, "component", {
|
|
|
431
431
|
},
|
|
432
432
|
reference: "owner"
|
|
433
433
|
});
|
|
434
|
-
|
|
434
|
+
const viewport = Symbol("View.viewport");
|
|
435
435
|
declare$(viewport, "component", {
|
|
436
436
|
type: {
|
|
437
437
|
"type": "array",
|
|
@@ -449,7 +449,7 @@ declare$(viewport, "component", {
|
|
|
449
449
|
1
|
|
450
450
|
]
|
|
451
451
|
});
|
|
452
|
-
|
|
452
|
+
const projection = Symbol("View.projection");
|
|
453
453
|
declare$(projection, "component", { type: {
|
|
454
454
|
"type": "array",
|
|
455
455
|
"items": {
|
|
@@ -460,11 +460,11 @@ declare$(projection, "component", { type: {
|
|
|
460
460
|
"maxItems": 16
|
|
461
461
|
} });
|
|
462
462
|
/** Each view's state on the world's device, by its entity: null until views are first updated. */
|
|
463
|
-
|
|
463
|
+
const states = Symbol("View.states");
|
|
464
464
|
declare$(states, "resource", {});
|
|
465
465
|
/** The uniform each view binds: its projection, then its size in pixels. */
|
|
466
|
-
|
|
467
|
-
|
|
466
|
+
const uniformBytes = 80;
|
|
467
|
+
const layouts = perDevice((device, _key) => device.createBindGroupLayout({
|
|
468
468
|
label: "view",
|
|
469
469
|
entries: [{
|
|
470
470
|
binding: 0,
|
|
@@ -473,10 +473,10 @@ var layouts = perDevice((device, _key) => device.createBindGroupLayout({
|
|
|
473
473
|
}]
|
|
474
474
|
}), () => "");
|
|
475
475
|
/** The bind group layout of a view's uniform, one per device: a pipeline's layout takes it at the group `wgsl` names. */
|
|
476
|
-
|
|
476
|
+
const layout = (device) => layouts(device, null);
|
|
477
477
|
/** The WGSL declarations of a view's uniform at bind group `group`: `view.projection` and `view.size`, in pixels. */
|
|
478
|
-
|
|
479
|
-
|
|
478
|
+
const wgsl = (group) => `struct View { projection: mat4x4f, size: vec2f }\n@group(${group}) @binding(0) var<uniform> view: View;\n`;
|
|
479
|
+
const rectangleOf = ([x, y, width, height], [targetWidth, targetHeight]) => {
|
|
480
480
|
const left = Math.min(targetWidth - 1, Math.max(0, Math.round(x * targetWidth)));
|
|
481
481
|
const top = Math.min(targetHeight - 1, Math.max(0, Math.round(y * targetHeight)));
|
|
482
482
|
return [
|
|
@@ -486,13 +486,13 @@ var rectangleOf = ([x, y, width, height], [targetWidth, targetHeight]) => {
|
|
|
486
486
|
Math.max(1, Math.min(targetHeight - top, Math.round(height * targetHeight)))
|
|
487
487
|
];
|
|
488
488
|
};
|
|
489
|
-
|
|
490
|
-
|
|
489
|
+
const sameRectangle = (a, b) => a.every((value, index) => value === b[index]);
|
|
490
|
+
const sameMatrix = (a, b) => a.every((value, index) => value === b[index]);
|
|
491
491
|
/**
|
|
492
492
|
* Each view placed in its target, its uniform written where its projection or rectangle changed; a view whose target
|
|
493
493
|
* has no textures, as without a device, has no state. Gives `previous` itself when nothing changed.
|
|
494
494
|
*/
|
|
495
|
-
|
|
495
|
+
const updated = (device, targets, previous, views) => {
|
|
496
496
|
const held = previous ?? /* @__PURE__ */ new Map();
|
|
497
497
|
let next = null;
|
|
498
498
|
for (let i = 0; i < views.length; i++) {
|
|
@@ -543,7 +543,7 @@ var updated = (device, targets, previous, views) => {
|
|
|
543
543
|
return next ?? held;
|
|
544
544
|
};
|
|
545
545
|
/** Destroys a view's uniform buffer when it stops being one. */
|
|
546
|
-
|
|
546
|
+
const release = Finalizer.create({ components: { with: [
|
|
547
547
|
target,
|
|
548
548
|
viewport,
|
|
549
549
|
projection
|
|
@@ -560,7 +560,7 @@ var release = Finalizer.create({ components: { with: [
|
|
|
560
560
|
* Begins a render pass drawing into a view: its target's textures, loading what they hold, limited to its rectangle,
|
|
561
561
|
* multisampled passes resolving into the target's color.
|
|
562
562
|
*/
|
|
563
|
-
|
|
563
|
+
const begin = (encoder, view, label) => {
|
|
564
564
|
const { color, multisampled, depth } = view.target;
|
|
565
565
|
const pass = encoder.beginRenderPass({
|
|
566
566
|
label,
|
|
@@ -589,11 +589,11 @@ function declare$(key, kind, declaration) {
|
|
|
589
589
|
}
|
|
590
590
|
//#endregion
|
|
591
591
|
//#region src/frame/frame.ts
|
|
592
|
-
|
|
592
|
+
const everyTarget = Index.create({
|
|
593
593
|
key: [],
|
|
594
594
|
components: { with: [options$1, size] }
|
|
595
595
|
});
|
|
596
|
-
|
|
596
|
+
const everySurface = Index.create({
|
|
597
597
|
key: [],
|
|
598
598
|
components: { with: [
|
|
599
599
|
canvas,
|
|
@@ -601,7 +601,7 @@ var everySurface = Index.create({
|
|
|
601
601
|
size
|
|
602
602
|
] }
|
|
603
603
|
});
|
|
604
|
-
|
|
604
|
+
const everyView = Index.create({
|
|
605
605
|
key: [],
|
|
606
606
|
components: { with: [
|
|
607
607
|
target,
|
|
@@ -614,7 +614,7 @@ var everyView = Index.create({
|
|
|
614
614
|
* target that declares a clear color: its color to that color and its depth to 1. Draws go after it and before
|
|
615
615
|
* `present`.
|
|
616
616
|
*/
|
|
617
|
-
|
|
617
|
+
const update = System.create({ lookup: {
|
|
618
618
|
targets: { index: everyTarget },
|
|
619
619
|
surfaces: { index: everySurface },
|
|
620
620
|
views: { index: everyView }
|
|
@@ -635,7 +635,7 @@ var update = System.create({ lookup: {
|
|
|
635
635
|
* Copies each surface's target into its canvas, in one body, so every draw of the run is in the frame the browser
|
|
636
636
|
* presents, even where the run waited between them.
|
|
637
637
|
*/
|
|
638
|
-
|
|
638
|
+
const present = System.render({
|
|
639
639
|
components: { with: [canvas] },
|
|
640
640
|
shader: { accessors: {} },
|
|
641
641
|
after: [update]
|
|
@@ -651,7 +651,7 @@ var present = System.render({
|
|
|
651
651
|
}
|
|
652
652
|
});
|
|
653
653
|
/** Every system of a frame, in order: targets, surfaces and views updated and targets cleared, then surfaces presented. */
|
|
654
|
-
|
|
654
|
+
const systems = System.create({ systems: [update, present] });
|
|
655
655
|
//#endregion
|
|
656
656
|
//#region src/frame/public.ts
|
|
657
657
|
var public_exports$2 = /* @__PURE__ */ __exportAll({
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Options","options","declare$","states","sameOptions","updated","release","declare$","states","Target.options","Target.size","updated","release","Target.resize","Target.options","Target.size","Surface.canvas","Surface.options","View.target","View.viewport","View.projection","Target.updated","Target.states","Surface.updated","Surface.states","View.updated","View.states"],"sources":["../src/cache/cache.ts","../src/cache/public.ts","../src/device/device.ts","../src/device/public.ts","../src/target/target.ts","../src/target/public.ts","../src/surface/surface.ts","../src/view/view.ts","../src/frame/frame.ts","../src/frame/public.ts","../src/surface/public.ts","../src/view/public.ts"],"sourcesContent":["// © 2026 Adobe. MIT License. See /LICENSE for details.\n\n/**\n * A cache of what `create` makes for each device and key: a pipeline, a layout, a sampler. Its values for a device go\n * with the device, so a device a world replaced, or one that was lost, holds nothing here. Keys are compared by\n * `keyOf`, by default their JSON.\n */\nexport const perDevice = <K, V>(create: (device: GPUDevice, key: K) => V, keyOf: (key: K) => string = key => JSON.stringify(key)): ((device: GPUDevice, key: K) => V) => {\n const devices = new WeakMap<GPUDevice, Map<string, { readonly value: V }>>();\n return (device, key) => {\n let made = devices.get(device);\n if (made === undefined) {\n made = new Map();\n devices.set(device, made);\n }\n const name = keyOf(key);\n const found = made.get(name);\n if (found !== undefined) return found.value;\n const value = create(device, key);\n made.set(name, { value });\n return value;\n };\n};\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { perDevice } from \"./cache.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { gpuDevice, System, type World } from \"@adobe/ecs\";\n\n/** What a device is requested with: the adapter's options, and the features and limits the device needs. */\nexport type Options = GPURequestAdapterOptions & {\n readonly requiredFeatures?: readonly GPUFeatureName[];\n readonly requiredLimits?: Readonly<Record<string, number>>;\n};\n\n/**\n * A device on this thread, or null where there's no WebGPU, no adapter for `options`, or the adapter refused the\n * device. Call it on the thread the world runs on: a device can't move between threads.\n */\nexport const request = async (options: Options = {}): Promise<GPUDevice | null> => {\n const { requiredFeatures, requiredLimits, ...adapterOptions } = options;\n const adapter = await globalThis.navigator?.gpu?.requestAdapter(adapterOptions);\n if (adapter === null || adapter === undefined) return null;\n try {\n return await adapter.requestDevice({ requiredFeatures, requiredLimits });\n } catch {\n return null;\n }\n};\n\n/** Sets the world's `gpuDevice`. */\nexport const set = System.create({}, ({ resources }, input: { readonly device: GPUDevice | null }) => {\n resources[gpuDevice] = input.device;\n});\n\n/**\n * Keeps the world supplied with a device: requests one now, and another each time the one it gave is lost. Resolves\n * once the first request settled, to whether it gave the world a device, and a function that stops keeping it. Call it\n * on the world's thread.\n */\nexport const keep = async (world: Pick<World, \"run\">, options: Options = {}): Promise<{ readonly supplied: boolean; readonly stop: () => void }> => {\n let stopped = false;\n const supply = async (): Promise<boolean> => {\n const device = await request(options);\n if (device === null || stopped) return false;\n await world.run(set, { device });\n void device.lost.then(() => { if (!stopped) void supply(); });\n return true;\n };\n const supplied = await supply();\n return { supplied, stop: () => { stopped = true; } };\n};\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { keep, request, set, type Options } from \"./device.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { type Entity, Finalizer, System, type Vec2, type Vec4 } from \"@adobe/ecs\";\n\n/**\n * What a render target draws into: its color format, null for the platform's preferred canvas format; its samples per\n * pixel, more than one drawing multisampled and resolving into its color; its depth format, null for none; and the\n * color it's cleared to each frame, null to keep what it holds.\n */\nexport type Options = {\n readonly format: GPUTextureFormat | null;\n readonly sampleCount: 1 | 4;\n readonly depthFormat: GPUTextureFormat | null;\n readonly clear: Vec4 | null;\n};\n\nexport const Options = {\n default: { format: null, sampleCount: 1, depthFormat: \"depth24plus\", clear: [0, 0, 0, 1] },\n} as const;\n\n/**\n * A target's textures on the world's device. `color` holds what's drawn, single-sampled, for reading and presenting;\n * with more than one sample, passes draw into `multisampled` and resolve into `color`. `size` is in pixels.\n */\nexport type State = {\n readonly entity: Entity;\n readonly device: GPUDevice;\n readonly options: Options;\n readonly format: GPUTextureFormat;\n readonly size: Vec2.U32;\n readonly color: GPUTexture;\n readonly multisampled: GPUTexture | null;\n readonly depth: GPUTexture | null;\n};\n\n/** An entity with these is a render target: what its textures are, and their size in pixels. */\nexport const options = Symbol(\"Target.options\");\nexport const size = Symbol(\"Target.size\");\n/** Each render target's textures on the world's device, by its entity: null until targets are first updated. */\nexport const states = Symbol(\"Target.states\");\n\ndeclare module \"@adobe/ecs\" {\n interface Components {\n [options]: { type: Options };\n [size]: { type: Vec2.U32 };\n }\n interface Resources {\n [states]: { type: ReadonlyMap<Entity, State> | null };\n }\n}\n\nconst sameOptions = (a: Options, b: Options): boolean =>\n a.format === b.format && a.sampleCount === b.sampleCount && a.depthFormat === b.depthFormat\n && (a.clear === b.clear || (a.clear !== null && b.clear !== null && a.clear.every((value, index) => value === b.clear?.[index])));\n\nconst destroyTextures = (state: State): void => {\n state.color.destroy();\n state.multisampled?.destroy();\n state.depth?.destroy();\n};\n\nconst created = (device: GPUDevice, entity: Entity, declared: Options, [width, height]: Vec2.U32): State => {\n const format = declared.format ?? navigator.gpu.getPreferredCanvasFormat();\n const extent = [width, height];\n const color = device.createTexture({\n label: `target ${entity} color`, size: extent, format,\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,\n });\n const multisampled = declared.sampleCount === 1 ? null : device.createTexture({\n label: `target ${entity} multisampled`, size: extent, format, sampleCount: declared.sampleCount, usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n const depth = declared.depthFormat === null ? null : device.createTexture({\n label: `target ${entity} depth`, size: extent, format: declared.depthFormat, sampleCount: declared.sampleCount,\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n });\n return { entity, device, options: declared, format, size: [width, height], color, multisampled, depth };\n};\n\n/** A render target as an index lists it: its entity, options and size. */\nexport type Listed = { readonly entity: Entity; readonly [options]: Options; readonly [size]: Vec2.U32 };\n\n/**\n * Each render target's textures on `device`, made again where its options, its size or the device changed, destroying\n * those they replace; with no device, none. Gives `previous` itself when nothing changed.\n */\nexport const updated = (device: GPUDevice | null, previous: ReadonlyMap<Entity, State> | null, targets: { readonly length: number; at(index: number): Listed }): ReadonlyMap<Entity, State> => {\n const held = previous ?? new Map<Entity, State>();\n let next: Map<Entity, State> | null = null;\n for (let i = 0; i < targets.length; i++) {\n const target = targets.at(i);\n const old = held.get(target.entity);\n const [width, height] = target[size];\n if (device !== null && old !== undefined && old.device === device && old.size[0] === width && old.size[1] === height && sameOptions(old.options, target[options])) continue;\n if (device === null && old === undefined) continue;\n next ??= new Map(held);\n if (old !== undefined) destroyTextures(old);\n if (device === null) next.delete(target.entity);\n else next.set(target.entity, created(device, target.entity, target[options], target[size]));\n }\n return next ?? held;\n};\n\n/** Records clearing each target that declares a clear color: its color to that color, and its depth to 1. */\nexport const recordClears = (encoder: GPUCommandEncoder, targets: ReadonlyMap<Entity, State>): void => {\n for (const target of targets.values()) {\n const color = target.options.clear;\n if (color === null) continue;\n const [r, g, b, a] = color;\n encoder.beginRenderPass({\n label: `clear target ${target.entity}`,\n colorAttachments: [{\n view: (target.multisampled ?? target.color).createView(), resolveTarget: target.multisampled === null ? undefined : target.color.createView(),\n clearValue: { r, g, b, a }, loadOp: \"clear\", storeOp: \"store\",\n }],\n depthStencilAttachment: target.depth === null ? undefined : { view: target.depth.createView(), depthClearValue: 1, depthLoadOp: \"clear\", depthStoreOp: \"store\" },\n }).end();\n }\n};\n\n/** Destroys a render target's textures when it stops being one. */\nexport const release = Finalizer.create({ components: { with: [options, size] } }, (target, { resources }) => {\n const current = resources[states];\n const state = current?.get(target.entity);\n if (current === null || state === undefined) return;\n destroyTextures(state);\n const next = new Map(current);\n next.delete(target.entity);\n resources[states] = next;\n});\n\n/** Sets a render target's size in pixels, at least one by one. */\nexport const resize = System.create({ components: { with: [size] }, target: \"target\" }, (row, _context, input: { readonly target: Entity; readonly width: number; readonly height: number }) => {\n row[size] = [Math.max(1, Math.floor(input.width)), Math.max(1, Math.floor(input.height))];\n});\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { Options, options, release, resize, size, states, type State } from \"./target.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { type Entity, Finalizer, System, type Vec2, type World } from \"@adobe/ecs\";\nimport * as Target from \"../target/public.js\";\n\n/** How a surface presents: how its alpha composites with the page, its color space, and its tone mapping. */\nexport type Options = {\n readonly alphaMode: GPUCanvasAlphaMode;\n readonly colorSpace: PredefinedColorSpace;\n readonly toneMapping: GPUCanvasToneMappingMode;\n};\n\nexport const Options = {\n default: { alphaMode: \"opaque\", colorSpace: \"srgb\", toneMapping: \"standard\" },\n} as const;\n\n/** A surface's canvas, configured for the world's device in its target's format. */\nexport type State = {\n readonly entity: Entity;\n readonly canvas: OffscreenCanvas;\n readonly context: GPUCanvasContext;\n readonly device: GPUDevice;\n readonly format: GPUTextureFormat;\n readonly options: Options;\n};\n\n/**\n * A render target with these presents to a canvas: the canvas, on the world's thread, and how it presents. The\n * canvas's size follows the target's.\n */\nexport const canvas = Symbol(\"Surface.canvas\");\nexport const options = Symbol(\"Surface.options\");\n/** Each surface's configured canvas, by its entity: null until surfaces are first updated. */\nexport const states = Symbol(\"Surface.states\");\n\ndeclare module \"@adobe/ecs\" {\n interface Components {\n [canvas]: { type: OffscreenCanvas; transfer: true };\n [options]: { type: Options };\n }\n interface Resources {\n [states]: { type: ReadonlyMap<Entity, State> | null };\n }\n}\n\n/**\n * A surface presenting to `canvas`, moved to the world's thread, of `width` by `height` pixels: a canvas's\n * `transferControlToOffscreen()`, or an `OffscreenCanvas` of its own. Resolves to its entity.\n */\nexport const attach = System.create({}, ({ commands }, input: {\n readonly canvas: OffscreenCanvas;\n readonly width: number;\n readonly height: number;\n readonly target?: Target.Options;\n readonly surface?: Options;\n}) => commands.spawn([Target.options, Target.size, canvas, options])({\n [Target.options]: input.target ?? Target.Options.default,\n [Target.size]: [Math.max(1, Math.floor(input.width)), Math.max(1, Math.floor(input.height))],\n [canvas]: input.canvas,\n [options]: input.surface ?? Options.default,\n}));\n\nconst sameOptions = (a: Options, b: Options): boolean => a.alphaMode === b.alphaMode && a.colorSpace === b.colorSpace && a.toneMapping === b.toneMapping;\n\n/** A surface as an index lists it: its entity, canvas, options and its target's size. */\nexport type Listed = { readonly entity: Entity; readonly [canvas]: OffscreenCanvas; readonly [options]: Options; readonly [Target.size]: Vec2.U32 };\n\n/**\n * Each surface's canvas sized to its target and configured for `device` in its target's format, again where either\n * changed; with no device, or no target state, unconfigured. Gives `previous` itself when nothing changed.\n */\nexport const updated = (device: GPUDevice | null, targets: ReadonlyMap<Entity, Target.State>, previous: ReadonlyMap<Entity, State> | null, surfaces: { readonly length: number; at(index: number): Listed }): ReadonlyMap<Entity, State> => {\n const held = previous ?? new Map<Entity, State>();\n let next: Map<Entity, State> | null = null;\n for (let i = 0; i < surfaces.length; i++) {\n const surface = surfaces.at(i);\n const presented = surface[canvas];\n const [width, height] = surface[Target.size];\n if (presented.width !== width) presented.width = width;\n if (presented.height !== height) presented.height = height;\n const target = targets.get(surface.entity);\n const old = held.get(surface.entity);\n if (device === null || target === undefined) {\n if (old === undefined) continue;\n old.context.unconfigure();\n next ??= new Map(held);\n next.delete(surface.entity);\n continue;\n }\n const declared = surface[options];\n if (old !== undefined && old.device === device && old.format === target.format && old.canvas === presented && sameOptions(old.options, declared)) continue;\n const context = presented.getContext(\"webgpu\");\n if (context === null) continue;\n context.configure({\n device, format: target.format, usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_DST,\n alphaMode: declared.alphaMode, colorSpace: declared.colorSpace, toneMapping: { mode: declared.toneMapping },\n });\n next ??= new Map(held);\n next.set(surface.entity, { entity: surface.entity, canvas: presented, context, device, format: target.format, options: declared });\n }\n return next ?? held;\n};\n\n/** Unconfigures a surface's canvas when it stops being one. */\nexport const release = Finalizer.create({ components: { with: [canvas] } }, (surface, { resources }) => {\n const current = resources[states];\n const state = current?.get(surface.entity);\n if (current === null || state === undefined) return;\n state.context.unconfigure();\n const next = new Map(current);\n next.delete(surface.entity);\n resources[states] = next;\n});\n\n/** A canvas's size in device pixels, from what a `ResizeObserver` saw of it. */\nconst pixelsOf = (entry: ResizeObserverEntry): readonly [number, number] => {\n const [device] = entry.devicePixelContentBoxSize ?? [];\n if (device !== undefined) return [device.inlineSize, device.blockSize];\n const [box] = entry.contentBoxSize;\n const scale = globalThis.devicePixelRatio ?? 1;\n return box === undefined ? [entry.contentRect.width * scale, entry.contentRect.height * scale] : [box.inlineSize * scale, box.blockSize * scale];\n};\n\n/**\n * Keeps a surface's size the size of `element` on the page, in device pixels, on the thread the page is on: the world\n * may be here or on a worker that joined it. Returns a function that stops.\n */\nexport const observe = (element: Element, world: Pick<World, \"run\">, surface: Entity): (() => void) => {\n const observer = new ResizeObserver(entries => {\n const entry = entries.at(-1);\n if (entry === undefined) return;\n const [width, height] = pixelsOf(entry);\n world.run(Target.resize, { target: surface, width, height }).catch(reportError);\n });\n try {\n observer.observe(element, { box: \"device-pixel-content-box\" });\n } catch {\n observer.observe(element);\n }\n return () => observer.disconnect();\n};\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { type Entity, Finalizer, type Mat4x4, type Vec4 } from \"@adobe/ecs\";\nimport { perDevice } from \"../cache/cache.js\";\nimport * as Target from \"../target/public.js\";\n\n/**\n * A view's place on its target's device: the target, its rectangle in the target in pixels (`x`, `y`, `width`,\n * `height`), and the uniform buffer and bind group holding its projection and size, for `wgsl`'s declarations.\n */\nexport type State = {\n readonly entity: Entity;\n readonly target: Target.State;\n readonly rectangle: readonly [number, number, number, number];\n readonly projection: Mat4x4;\n readonly buffer: GPUBuffer;\n readonly bindGroup: GPUBindGroup;\n};\n\n/**\n * An entity with these is a view: the render target it draws into, which owns it; its rectangle in that target as\n * fractions of its size (`x`, `y`, `width`, `height`); and the matrix taking its scene to clip space.\n */\nexport const target = Symbol(\"View.target\");\nexport const viewport = Symbol(\"View.viewport\");\nexport const projection = Symbol(\"View.projection\");\n/** Each view's state on the world's device, by its entity: null until views are first updated. */\nexport const states = Symbol(\"View.states\");\n\ndeclare module \"@adobe/ecs\" {\n interface Components {\n [target]: { type: Entity; reference: \"owner\" };\n [viewport]: { type: Vec4; default: [0, 0, 1, 1] };\n [projection]: { type: Mat4x4 };\n }\n interface Resources {\n [states]: { type: ReadonlyMap<Entity, State> | null };\n }\n}\n\n/** The uniform each view binds: its projection, then its size in pixels. */\nconst uniformBytes = 80;\n\nconst layouts = perDevice((device: GPUDevice, _key: null) => device.createBindGroupLayout({\n label: \"view\",\n entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } }],\n}), () => \"\");\n\n/** The bind group layout of a view's uniform, one per device: a pipeline's layout takes it at the group `wgsl` names. */\nexport const layout = (device: GPUDevice): GPUBindGroupLayout => layouts(device, null);\n\n/** The WGSL declarations of a view's uniform at bind group `group`: `view.projection` and `view.size`, in pixels. */\nexport const wgsl = (group: number): string =>\n `struct View { projection: mat4x4f, size: vec2f }\\n@group(${group}) @binding(0) var<uniform> view: View;\\n`;\n\nconst rectangleOf = ([x, y, width, height]: Vec4, [targetWidth, targetHeight]: readonly [number, number]): readonly [number, number, number, number] => {\n const left = Math.min(targetWidth - 1, Math.max(0, Math.round(x * targetWidth)));\n const top = Math.min(targetHeight - 1, Math.max(0, Math.round(y * targetHeight)));\n return [left, top, Math.max(1, Math.min(targetWidth - left, Math.round(width * targetWidth))), Math.max(1, Math.min(targetHeight - top, Math.round(height * targetHeight)))];\n};\n\nconst sameRectangle = (a: readonly number[], b: readonly number[]): boolean => a.every((value, index) => value === b[index]);\nconst sameMatrix = (a: Mat4x4, b: Mat4x4): boolean => a.every((value, index) => value === b[index]);\n\n/** A view as an index lists it: its entity, target, viewport and projection. */\nexport type Listed = { readonly entity: Entity; readonly [target]: Entity; readonly [viewport]: Vec4; readonly [projection]: Mat4x4 };\n\n/**\n * Each view placed in its target, its uniform written where its projection or rectangle changed; a view whose target\n * has no textures, as without a device, has no state. Gives `previous` itself when nothing changed.\n */\nexport const updated = (device: GPUDevice | null, targets: ReadonlyMap<Entity, Target.State>, previous: ReadonlyMap<Entity, State> | null, views: { readonly length: number; at(index: number): Listed }): ReadonlyMap<Entity, State> => {\n const held = previous ?? new Map<Entity, State>();\n let next: Map<Entity, State> | null = null;\n for (let i = 0; i < views.length; i++) {\n const view = views.at(i);\n const old = held.get(view.entity);\n const drawn = device === null ? undefined : targets.get(view[target]);\n if (device === null || drawn === undefined) {\n if (old === undefined) continue;\n old.buffer.destroy();\n next ??= new Map(held);\n next.delete(view.entity);\n continue;\n }\n const rectangle = rectangleOf(view[viewport], drawn.size);\n const matrix = view[projection];\n if (old !== undefined && old.target === drawn && sameRectangle(old.rectangle, rectangle) && sameMatrix(old.projection, matrix)) continue;\n const kept = old !== undefined && old.target.device === device;\n if (old !== undefined && !kept) old.buffer.destroy();\n const buffer = kept ? old.buffer : device.createBuffer({ label: `view ${view.entity}`, size: uniformBytes, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });\n const bindGroup = kept ? old.bindGroup : device.createBindGroup({ layout: layout(device), entries: [{ binding: 0, resource: { buffer } }] });\n device.queue.writeBuffer(buffer, 0, new Float32Array([...matrix, rectangle[2], rectangle[3], 0, 0]));\n next ??= new Map(held);\n next.set(view.entity, { entity: view.entity, target: drawn, rectangle, projection: matrix, buffer, bindGroup });\n }\n return next ?? held;\n};\n\n/** Destroys a view's uniform buffer when it stops being one. */\nexport const release = Finalizer.create({ components: { with: [target, viewport, projection] } }, (view, { resources }) => {\n const current = resources[states];\n const state = current?.get(view.entity);\n if (current === null || state === undefined) return;\n state.buffer.destroy();\n const next = new Map(current);\n next.delete(view.entity);\n resources[states] = next;\n});\n\n/**\n * Begins a render pass drawing into a view: its target's textures, loading what they hold, limited to its rectangle,\n * multisampled passes resolving into the target's color.\n */\nexport const begin = (encoder: GPUCommandEncoder, view: State, label?: string): GPURenderPassEncoder => {\n const { color, multisampled, depth } = view.target;\n const pass = encoder.beginRenderPass({\n label,\n colorAttachments: [{ view: (multisampled ?? color).createView(), resolveTarget: multisampled === null ? undefined : color.createView(), loadOp: \"load\", storeOp: \"store\" }],\n depthStencilAttachment: depth === null ? undefined : { view: depth.createView(), depthLoadOp: \"load\", depthStoreOp: \"store\" },\n });\n const [x, y, width, height] = view.rectangle;\n pass.setViewport(x, y, width, height, 0, 1);\n pass.setScissorRect(x, y, width, height);\n return pass;\n};\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { gpuDevice, Index, System } from \"@adobe/ecs\";\nimport * as Surface from \"../surface/surface.js\";\nimport * as Target from \"../target/target.js\";\nimport * as View from \"../view/view.js\";\n\nconst everyTarget = Index.create({ key: [], components: { with: [Target.options, Target.size] } });\nconst everySurface = Index.create({ key: [], components: { with: [Surface.canvas, Surface.options, Target.size] } });\nconst everyView = Index.create({ key: [], components: { with: [View.target, View.viewport, View.projection] } });\n\n/**\n * Brings render targets, surfaces and views up to date with their entities and the world's device, then clears each\n * target that declares a clear color: its color to that color and its depth to 1. Draws go after it and before\n * `present`.\n */\nexport const update = System.create({\n lookup: { targets: { index: everyTarget }, surfaces: { index: everySurface }, views: { index: everyView } },\n}, ({ resources, lookup }) => {\n const device = resources[gpuDevice];\n const targets = Target.updated(device, resources[Target.states], lookup.targets());\n const surfaces = Surface.updated(device, targets, resources[Surface.states], lookup.surfaces());\n const views = View.updated(device, targets, resources[View.states], lookup.views());\n if (targets !== resources[Target.states]) resources[Target.states] = targets;\n if (surfaces !== resources[Surface.states]) resources[Surface.states] = surfaces;\n if (views !== resources[View.states]) resources[View.states] = views;\n if (device === null || targets.size === 0) return;\n const encoder = device.createCommandEncoder({ label: \"clear targets\" });\n Target.recordClears(encoder, targets);\n device.queue.submit([encoder.finish()]);\n});\n\n/**\n * Copies each surface's target into its canvas, in one body, so every draw of the run is in the frame the browser\n * presents, even where the run waited between them.\n */\nexport const present = System.render({\n components: { with: [Surface.canvas] },\n shader: { accessors: {} },\n after: [update],\n}, ({ encoder }, { resources }) => {\n const targets = resources[Target.states];\n for (const surface of resources[Surface.states]?.values() ?? []) {\n const target = targets?.get(surface.entity);\n if (target === undefined || target.device !== surface.device) continue;\n const current = surface.context.getCurrentTexture();\n const [width, height] = target.size;\n if (current.width !== width || current.height !== height) continue;\n encoder.copyTextureToTexture({ texture: target.color }, { texture: current }, [width, height]);\n }\n});\n\n/** Every system of a frame, in order: targets, surfaces and views updated and targets cleared, then surfaces presented. */\nexport const systems = System.create({ systems: [update, present] });\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { present, systems, update } from \"./frame.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { attach, canvas, observe, Options, options, release, states, type State } from \"./surface.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { begin, layout, projection, release, states, target, viewport, wgsl, type State } from \"./view.js\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["Options","options","declare$","states","sameOptions","updated","release","declare$","states","Target.options","Target.size","updated","release","Target.resize","Target.options","Target.size","Surface.canvas","Surface.options","View.target","View.viewport","View.projection","Target.updated","Target.states","Surface.updated","Surface.states","View.updated","View.states"],"sources":["../src/cache/cache.ts","../src/cache/public.ts","../src/device/device.ts","../src/device/public.ts","../src/target/target.ts","../src/target/public.ts","../src/surface/surface.ts","../src/view/view.ts","../src/frame/frame.ts","../src/frame/public.ts","../src/surface/public.ts","../src/view/public.ts"],"sourcesContent":["// © 2026 Adobe. MIT License. See /LICENSE for details.\n\n/**\n * A cache of what `create` makes for each device and key: a pipeline, a layout, a sampler. Its values for a device go\n * with the device, so a device a world replaced, or one that was lost, holds nothing here. Keys are compared by\n * `keyOf`, by default their JSON.\n */\nexport const perDevice = <K, V>(create: (device: GPUDevice, key: K) => V, keyOf: (key: K) => string = key => JSON.stringify(key)): ((device: GPUDevice, key: K) => V) => {\n const devices = new WeakMap<GPUDevice, Map<string, { readonly value: V }>>();\n return (device, key) => {\n let made = devices.get(device);\n if (made === undefined) {\n made = new Map();\n devices.set(device, made);\n }\n const name = keyOf(key);\n const found = made.get(name);\n if (found !== undefined) return found.value;\n const value = create(device, key);\n made.set(name, { value });\n return value;\n };\n};\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { perDevice } from \"./cache.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { gpuDevice, System, type World } from \"@adobe/ecs\";\n\n/** What a device is requested with: the adapter's options, and the features and limits the device needs. */\nexport type Options = GPURequestAdapterOptions & {\n readonly requiredFeatures?: readonly GPUFeatureName[];\n readonly requiredLimits?: Readonly<Record<string, number>>;\n};\n\n/**\n * A device on this thread, or null where there's no WebGPU, no adapter for `options`, or the adapter refused the\n * device. Call it on the thread the world runs on: a device can't move between threads.\n */\nexport const request = async (options: Options = {}): Promise<GPUDevice | null> => {\n const { requiredFeatures, requiredLimits, ...adapterOptions } = options;\n const adapter = await globalThis.navigator?.gpu?.requestAdapter(adapterOptions);\n if (adapter === null || adapter === undefined) return null;\n try {\n return await adapter.requestDevice({ requiredFeatures, requiredLimits });\n } catch {\n return null;\n }\n};\n\n/** Sets the world's `gpuDevice`. */\nexport const set = System.create({}, ({ resources }, input: { readonly device: GPUDevice | null }) => {\n resources[gpuDevice] = input.device;\n});\n\n/**\n * Keeps the world supplied with a device: requests one now, and another each time the one it gave is lost. Resolves\n * once the first request settled, to whether it gave the world a device, and a function that stops keeping it. Call it\n * on the world's thread.\n */\nexport const keep = async (world: Pick<World, \"run\">, options: Options = {}): Promise<{ readonly supplied: boolean; readonly stop: () => void }> => {\n let stopped = false;\n const supply = async (): Promise<boolean> => {\n const device = await request(options);\n if (device === null || stopped) return false;\n await world.run(set, { device });\n void device.lost.then(() => { if (!stopped) void supply(); });\n return true;\n };\n const supplied = await supply();\n return { supplied, stop: () => { stopped = true; } };\n};\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { keep, request, set, type Options } from \"./device.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { type Entity, Finalizer, System, type Vec2, type Vec4 } from \"@adobe/ecs\";\n\n/**\n * What a render target draws into: its color format, null for the platform's preferred canvas format; its samples per\n * pixel, more than one drawing multisampled and resolving into its color; its depth format, null for none; and the\n * color it's cleared to each frame, null to keep what it holds.\n */\nexport type Options = {\n readonly format: GPUTextureFormat | null;\n readonly sampleCount: 1 | 4;\n readonly depthFormat: GPUTextureFormat | null;\n readonly clear: Vec4 | null;\n};\n\nexport const Options = {\n default: { format: null, sampleCount: 1, depthFormat: \"depth24plus\", clear: [0, 0, 0, 1] },\n} as const;\n\n/**\n * A target's textures on the world's device. `color` holds what's drawn, single-sampled, for reading and presenting;\n * with more than one sample, passes draw into `multisampled` and resolve into `color`. `size` is in pixels.\n */\nexport type State = {\n readonly entity: Entity;\n readonly device: GPUDevice;\n readonly options: Options;\n readonly format: GPUTextureFormat;\n readonly size: Vec2.U32;\n readonly color: GPUTexture;\n readonly multisampled: GPUTexture | null;\n readonly depth: GPUTexture | null;\n};\n\n/** An entity with these is a render target: what its textures are, and their size in pixels. */\nexport const options = Symbol(\"Target.options\");\nexport const size = Symbol(\"Target.size\");\n/** Each render target's textures on the world's device, by its entity: null until targets are first updated. */\nexport const states = Symbol(\"Target.states\");\n\ndeclare module \"@adobe/ecs\" {\n interface Components {\n [options]: { type: Options };\n [size]: { type: Vec2.U32 };\n }\n interface Resources {\n [states]: { type: ReadonlyMap<Entity, State> | null };\n }\n}\n\nconst sameOptions = (a: Options, b: Options): boolean =>\n a.format === b.format && a.sampleCount === b.sampleCount && a.depthFormat === b.depthFormat\n && (a.clear === b.clear || (a.clear !== null && b.clear !== null && a.clear.every((value, index) => value === b.clear?.[index])));\n\nconst destroyTextures = (state: State): void => {\n state.color.destroy();\n state.multisampled?.destroy();\n state.depth?.destroy();\n};\n\nconst created = (device: GPUDevice, entity: Entity, declared: Options, [width, height]: Vec2.U32): State => {\n const format = declared.format ?? navigator.gpu.getPreferredCanvasFormat();\n const extent = [width, height];\n const color = device.createTexture({\n label: `target ${entity} color`, size: extent, format,\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,\n });\n const multisampled = declared.sampleCount === 1 ? null : device.createTexture({\n label: `target ${entity} multisampled`, size: extent, format, sampleCount: declared.sampleCount, usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n const depth = declared.depthFormat === null ? null : device.createTexture({\n label: `target ${entity} depth`, size: extent, format: declared.depthFormat, sampleCount: declared.sampleCount,\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n });\n return { entity, device, options: declared, format, size: [width, height], color, multisampled, depth };\n};\n\n/** A render target as an index lists it: its entity, options and size. */\nexport type Listed = { readonly entity: Entity; readonly [options]: Options; readonly [size]: Vec2.U32 };\n\n/**\n * Each render target's textures on `device`, made again where its options, its size or the device changed, destroying\n * those they replace; with no device, none. Gives `previous` itself when nothing changed.\n */\nexport const updated = (device: GPUDevice | null, previous: ReadonlyMap<Entity, State> | null, targets: { readonly length: number; at(index: number): Listed }): ReadonlyMap<Entity, State> => {\n const held = previous ?? new Map<Entity, State>();\n let next: Map<Entity, State> | null = null;\n for (let i = 0; i < targets.length; i++) {\n const target = targets.at(i);\n const old = held.get(target.entity);\n const [width, height] = target[size];\n if (device !== null && old !== undefined && old.device === device && old.size[0] === width && old.size[1] === height && sameOptions(old.options, target[options])) continue;\n if (device === null && old === undefined) continue;\n next ??= new Map(held);\n if (old !== undefined) destroyTextures(old);\n if (device === null) next.delete(target.entity);\n else next.set(target.entity, created(device, target.entity, target[options], target[size]));\n }\n return next ?? held;\n};\n\n/** Records clearing each target that declares a clear color: its color to that color, and its depth to 1. */\nexport const recordClears = (encoder: GPUCommandEncoder, targets: ReadonlyMap<Entity, State>): void => {\n for (const target of targets.values()) {\n const color = target.options.clear;\n if (color === null) continue;\n const [r, g, b, a] = color;\n encoder.beginRenderPass({\n label: `clear target ${target.entity}`,\n colorAttachments: [{\n view: (target.multisampled ?? target.color).createView(), resolveTarget: target.multisampled === null ? undefined : target.color.createView(),\n clearValue: { r, g, b, a }, loadOp: \"clear\", storeOp: \"store\",\n }],\n depthStencilAttachment: target.depth === null ? undefined : { view: target.depth.createView(), depthClearValue: 1, depthLoadOp: \"clear\", depthStoreOp: \"store\" },\n }).end();\n }\n};\n\n/** Destroys a render target's textures when it stops being one. */\nexport const release = Finalizer.create({ components: { with: [options, size] } }, (target, { resources }) => {\n const current = resources[states];\n const state = current?.get(target.entity);\n if (current === null || state === undefined) return;\n destroyTextures(state);\n const next = new Map(current);\n next.delete(target.entity);\n resources[states] = next;\n});\n\n/** Sets a render target's size in pixels, at least one by one. */\nexport const resize = System.create({ components: { with: [size] }, target: \"target\" }, (row, _context, input: { readonly target: Entity; readonly width: number; readonly height: number }) => {\n row[size] = [Math.max(1, Math.floor(input.width)), Math.max(1, Math.floor(input.height))];\n});\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { Options, options, release, resize, size, states, type State } from \"./target.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { type Entity, Finalizer, System, type Vec2, type World } from \"@adobe/ecs\";\nimport * as Target from \"../target/public.js\";\n\n/** How a surface presents: how its alpha composites with the page, its color space, and its tone mapping. */\nexport type Options = {\n readonly alphaMode: GPUCanvasAlphaMode;\n readonly colorSpace: PredefinedColorSpace;\n readonly toneMapping: GPUCanvasToneMappingMode;\n};\n\nexport const Options = {\n default: { alphaMode: \"opaque\", colorSpace: \"srgb\", toneMapping: \"standard\" },\n} as const;\n\n/** A surface's canvas, configured for the world's device in its target's format. */\nexport type State = {\n readonly entity: Entity;\n readonly canvas: OffscreenCanvas;\n readonly context: GPUCanvasContext;\n readonly device: GPUDevice;\n readonly format: GPUTextureFormat;\n readonly options: Options;\n};\n\n/**\n * A render target with these presents to a canvas: the canvas, on the world's thread, and how it presents. The\n * canvas's size follows the target's.\n */\nexport const canvas = Symbol(\"Surface.canvas\");\nexport const options = Symbol(\"Surface.options\");\n/** Each surface's configured canvas, by its entity: null until surfaces are first updated. */\nexport const states = Symbol(\"Surface.states\");\n\ndeclare module \"@adobe/ecs\" {\n interface Components {\n [canvas]: { type: OffscreenCanvas; transfer: true };\n [options]: { type: Options };\n }\n interface Resources {\n [states]: { type: ReadonlyMap<Entity, State> | null };\n }\n}\n\n/**\n * A surface presenting to `canvas`, moved to the world's thread, of `width` by `height` pixels: a canvas's\n * `transferControlToOffscreen()`, or an `OffscreenCanvas` of its own. Resolves to its entity.\n */\nexport const attach = System.create({}, ({ commands }, input: {\n readonly canvas: OffscreenCanvas;\n readonly width: number;\n readonly height: number;\n readonly target?: Target.Options;\n readonly surface?: Options;\n}) => commands.spawn([Target.options, Target.size, canvas, options])({\n [Target.options]: input.target ?? Target.Options.default,\n [Target.size]: [Math.max(1, Math.floor(input.width)), Math.max(1, Math.floor(input.height))],\n [canvas]: input.canvas,\n [options]: input.surface ?? Options.default,\n}));\n\nconst sameOptions = (a: Options, b: Options): boolean => a.alphaMode === b.alphaMode && a.colorSpace === b.colorSpace && a.toneMapping === b.toneMapping;\n\n/** A surface as an index lists it: its entity, canvas, options and its target's size. */\nexport type Listed = { readonly entity: Entity; readonly [canvas]: OffscreenCanvas; readonly [options]: Options; readonly [Target.size]: Vec2.U32 };\n\n/**\n * Each surface's canvas sized to its target and configured for `device` in its target's format, again where either\n * changed; with no device, or no target state, unconfigured. Gives `previous` itself when nothing changed.\n */\nexport const updated = (device: GPUDevice | null, targets: ReadonlyMap<Entity, Target.State>, previous: ReadonlyMap<Entity, State> | null, surfaces: { readonly length: number; at(index: number): Listed }): ReadonlyMap<Entity, State> => {\n const held = previous ?? new Map<Entity, State>();\n let next: Map<Entity, State> | null = null;\n for (let i = 0; i < surfaces.length; i++) {\n const surface = surfaces.at(i);\n const presented = surface[canvas];\n const [width, height] = surface[Target.size];\n if (presented.width !== width) presented.width = width;\n if (presented.height !== height) presented.height = height;\n const target = targets.get(surface.entity);\n const old = held.get(surface.entity);\n if (device === null || target === undefined) {\n if (old === undefined) continue;\n old.context.unconfigure();\n next ??= new Map(held);\n next.delete(surface.entity);\n continue;\n }\n const declared = surface[options];\n if (old !== undefined && old.device === device && old.format === target.format && old.canvas === presented && sameOptions(old.options, declared)) continue;\n const context = presented.getContext(\"webgpu\");\n if (context === null) continue;\n context.configure({\n device, format: target.format, usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_DST,\n alphaMode: declared.alphaMode, colorSpace: declared.colorSpace, toneMapping: { mode: declared.toneMapping },\n });\n next ??= new Map(held);\n next.set(surface.entity, { entity: surface.entity, canvas: presented, context, device, format: target.format, options: declared });\n }\n return next ?? held;\n};\n\n/** Unconfigures a surface's canvas when it stops being one. */\nexport const release = Finalizer.create({ components: { with: [canvas] } }, (surface, { resources }) => {\n const current = resources[states];\n const state = current?.get(surface.entity);\n if (current === null || state === undefined) return;\n state.context.unconfigure();\n const next = new Map(current);\n next.delete(surface.entity);\n resources[states] = next;\n});\n\n/** A canvas's size in device pixels, from what a `ResizeObserver` saw of it. */\nconst pixelsOf = (entry: ResizeObserverEntry): readonly [number, number] => {\n const [device] = entry.devicePixelContentBoxSize ?? [];\n if (device !== undefined) return [device.inlineSize, device.blockSize];\n const [box] = entry.contentBoxSize;\n const scale = globalThis.devicePixelRatio ?? 1;\n return box === undefined ? [entry.contentRect.width * scale, entry.contentRect.height * scale] : [box.inlineSize * scale, box.blockSize * scale];\n};\n\n/**\n * Keeps a surface's size the size of `element` on the page, in device pixels, on the thread the page is on: the world\n * may be here or on a worker that joined it. Returns a function that stops.\n */\nexport const observe = (element: Element, world: Pick<World, \"run\">, surface: Entity): (() => void) => {\n const observer = new ResizeObserver(entries => {\n const entry = entries.at(-1);\n if (entry === undefined) return;\n const [width, height] = pixelsOf(entry);\n world.run(Target.resize, { target: surface, width, height }).catch(reportError);\n });\n try {\n observer.observe(element, { box: \"device-pixel-content-box\" });\n } catch {\n observer.observe(element);\n }\n return () => observer.disconnect();\n};\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { type Entity, Finalizer, type Mat4x4, type Vec4 } from \"@adobe/ecs\";\nimport { perDevice } from \"../cache/cache.js\";\nimport * as Target from \"../target/public.js\";\n\n/**\n * A view's place on its target's device: the target, its rectangle in the target in pixels (`x`, `y`, `width`,\n * `height`), and the uniform buffer and bind group holding its projection and size, for `wgsl`'s declarations.\n */\nexport type State = {\n readonly entity: Entity;\n readonly target: Target.State;\n readonly rectangle: readonly [number, number, number, number];\n readonly projection: Mat4x4;\n readonly buffer: GPUBuffer;\n readonly bindGroup: GPUBindGroup;\n};\n\n/**\n * An entity with these is a view: the render target it draws into, which owns it; its rectangle in that target as\n * fractions of its size (`x`, `y`, `width`, `height`); and the matrix taking its scene to clip space.\n */\nexport const target = Symbol(\"View.target\");\nexport const viewport = Symbol(\"View.viewport\");\nexport const projection = Symbol(\"View.projection\");\n/** Each view's state on the world's device, by its entity: null until views are first updated. */\nexport const states = Symbol(\"View.states\");\n\ndeclare module \"@adobe/ecs\" {\n interface Components {\n [target]: { type: Entity; reference: \"owner\" };\n [viewport]: { type: Vec4; default: [0, 0, 1, 1] };\n [projection]: { type: Mat4x4 };\n }\n interface Resources {\n [states]: { type: ReadonlyMap<Entity, State> | null };\n }\n}\n\n/** The uniform each view binds: its projection, then its size in pixels. */\nconst uniformBytes = 80;\n\nconst layouts = perDevice((device: GPUDevice, _key: null) => device.createBindGroupLayout({\n label: \"view\",\n entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } }],\n}), () => \"\");\n\n/** The bind group layout of a view's uniform, one per device: a pipeline's layout takes it at the group `wgsl` names. */\nexport const layout = (device: GPUDevice): GPUBindGroupLayout => layouts(device, null);\n\n/** The WGSL declarations of a view's uniform at bind group `group`: `view.projection` and `view.size`, in pixels. */\nexport const wgsl = (group: number): string =>\n `struct View { projection: mat4x4f, size: vec2f }\\n@group(${group}) @binding(0) var<uniform> view: View;\\n`;\n\nconst rectangleOf = ([x, y, width, height]: Vec4, [targetWidth, targetHeight]: readonly [number, number]): readonly [number, number, number, number] => {\n const left = Math.min(targetWidth - 1, Math.max(0, Math.round(x * targetWidth)));\n const top = Math.min(targetHeight - 1, Math.max(0, Math.round(y * targetHeight)));\n return [left, top, Math.max(1, Math.min(targetWidth - left, Math.round(width * targetWidth))), Math.max(1, Math.min(targetHeight - top, Math.round(height * targetHeight)))];\n};\n\nconst sameRectangle = (a: readonly number[], b: readonly number[]): boolean => a.every((value, index) => value === b[index]);\nconst sameMatrix = (a: Mat4x4, b: Mat4x4): boolean => a.every((value, index) => value === b[index]);\n\n/** A view as an index lists it: its entity, target, viewport and projection. */\nexport type Listed = { readonly entity: Entity; readonly [target]: Entity; readonly [viewport]: Vec4; readonly [projection]: Mat4x4 };\n\n/**\n * Each view placed in its target, its uniform written where its projection or rectangle changed; a view whose target\n * has no textures, as without a device, has no state. Gives `previous` itself when nothing changed.\n */\nexport const updated = (device: GPUDevice | null, targets: ReadonlyMap<Entity, Target.State>, previous: ReadonlyMap<Entity, State> | null, views: { readonly length: number; at(index: number): Listed }): ReadonlyMap<Entity, State> => {\n const held = previous ?? new Map<Entity, State>();\n let next: Map<Entity, State> | null = null;\n for (let i = 0; i < views.length; i++) {\n const view = views.at(i);\n const old = held.get(view.entity);\n const drawn = device === null ? undefined : targets.get(view[target]);\n if (device === null || drawn === undefined) {\n if (old === undefined) continue;\n old.buffer.destroy();\n next ??= new Map(held);\n next.delete(view.entity);\n continue;\n }\n const rectangle = rectangleOf(view[viewport], drawn.size);\n const matrix = view[projection];\n if (old !== undefined && old.target === drawn && sameRectangle(old.rectangle, rectangle) && sameMatrix(old.projection, matrix)) continue;\n const kept = old !== undefined && old.target.device === device;\n if (old !== undefined && !kept) old.buffer.destroy();\n const buffer = kept ? old.buffer : device.createBuffer({ label: `view ${view.entity}`, size: uniformBytes, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });\n const bindGroup = kept ? old.bindGroup : device.createBindGroup({ layout: layout(device), entries: [{ binding: 0, resource: { buffer } }] });\n device.queue.writeBuffer(buffer, 0, new Float32Array([...matrix, rectangle[2], rectangle[3], 0, 0]));\n next ??= new Map(held);\n next.set(view.entity, { entity: view.entity, target: drawn, rectangle, projection: matrix, buffer, bindGroup });\n }\n return next ?? held;\n};\n\n/** Destroys a view's uniform buffer when it stops being one. */\nexport const release = Finalizer.create({ components: { with: [target, viewport, projection] } }, (view, { resources }) => {\n const current = resources[states];\n const state = current?.get(view.entity);\n if (current === null || state === undefined) return;\n state.buffer.destroy();\n const next = new Map(current);\n next.delete(view.entity);\n resources[states] = next;\n});\n\n/**\n * Begins a render pass drawing into a view: its target's textures, loading what they hold, limited to its rectangle,\n * multisampled passes resolving into the target's color.\n */\nexport const begin = (encoder: GPUCommandEncoder, view: State, label?: string): GPURenderPassEncoder => {\n const { color, multisampled, depth } = view.target;\n const pass = encoder.beginRenderPass({\n label,\n colorAttachments: [{ view: (multisampled ?? color).createView(), resolveTarget: multisampled === null ? undefined : color.createView(), loadOp: \"load\", storeOp: \"store\" }],\n depthStencilAttachment: depth === null ? undefined : { view: depth.createView(), depthLoadOp: \"load\", depthStoreOp: \"store\" },\n });\n const [x, y, width, height] = view.rectangle;\n pass.setViewport(x, y, width, height, 0, 1);\n pass.setScissorRect(x, y, width, height);\n return pass;\n};\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nimport { gpuDevice, Index, System } from \"@adobe/ecs\";\nimport * as Surface from \"../surface/surface.js\";\nimport * as Target from \"../target/target.js\";\nimport * as View from \"../view/view.js\";\n\nconst everyTarget = Index.create({ key: [], components: { with: [Target.options, Target.size] } });\nconst everySurface = Index.create({ key: [], components: { with: [Surface.canvas, Surface.options, Target.size] } });\nconst everyView = Index.create({ key: [], components: { with: [View.target, View.viewport, View.projection] } });\n\n/**\n * Brings render targets, surfaces and views up to date with their entities and the world's device, then clears each\n * target that declares a clear color: its color to that color and its depth to 1. Draws go after it and before\n * `present`.\n */\nexport const update = System.create({\n lookup: { targets: { index: everyTarget }, surfaces: { index: everySurface }, views: { index: everyView } },\n}, ({ resources, lookup }) => {\n const device = resources[gpuDevice];\n const targets = Target.updated(device, resources[Target.states], lookup.targets());\n const surfaces = Surface.updated(device, targets, resources[Surface.states], lookup.surfaces());\n const views = View.updated(device, targets, resources[View.states], lookup.views());\n if (targets !== resources[Target.states]) resources[Target.states] = targets;\n if (surfaces !== resources[Surface.states]) resources[Surface.states] = surfaces;\n if (views !== resources[View.states]) resources[View.states] = views;\n if (device === null || targets.size === 0) return;\n const encoder = device.createCommandEncoder({ label: \"clear targets\" });\n Target.recordClears(encoder, targets);\n device.queue.submit([encoder.finish()]);\n});\n\n/**\n * Copies each surface's target into its canvas, in one body, so every draw of the run is in the frame the browser\n * presents, even where the run waited between them.\n */\nexport const present = System.render({\n components: { with: [Surface.canvas] },\n shader: { accessors: {} },\n after: [update],\n}, ({ encoder }, { resources }) => {\n const targets = resources[Target.states];\n for (const surface of resources[Surface.states]?.values() ?? []) {\n const target = targets?.get(surface.entity);\n if (target === undefined || target.device !== surface.device) continue;\n const current = surface.context.getCurrentTexture();\n const [width, height] = target.size;\n if (current.width !== width || current.height !== height) continue;\n encoder.copyTextureToTexture({ texture: target.color }, { texture: current }, [width, height]);\n }\n});\n\n/** Every system of a frame, in order: targets, surfaces and views updated and targets cleared, then surfaces presented. */\nexport const systems = System.create({ systems: [update, present] });\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { present, systems, update } from \"./frame.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { attach, canvas, observe, Options, options, release, states, type State } from \"./surface.js\";\n","// © 2026 Adobe. MIT License. See /LICENSE for details.\nexport { begin, layout, projection, release, states, target, viewport, wgsl, type State } from \"./view.js\";\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const main: () => Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const main: () => Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/ecs-gpu",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "WebGPU devices, surfaces, render targets, views and frame passes for @adobe/ecs",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"LICENSE"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@adobe/ecs": "0.2.
|
|
23
|
+
"@adobe/ecs": "0.2.4"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^25.6.0",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"playwright": "^1.64.1",
|
|
30
30
|
"typescript": "^5.8.3",
|
|
31
31
|
"vite": "^8.3.4",
|
|
32
|
-
"vitest": "^5.0.5"
|
|
32
|
+
"vitest": "^5.0.5",
|
|
33
|
+
"ecs-guide-checks": "0.0.0"
|
|
33
34
|
},
|
|
34
35
|
"exports": {
|
|
35
36
|
".": {
|
|
@@ -37,6 +38,12 @@
|
|
|
37
38
|
"types": "./dist/types/index.d.ts"
|
|
38
39
|
}
|
|
39
40
|
},
|
|
41
|
+
"guide": {
|
|
42
|
+
"files": [
|
|
43
|
+
"src/**/*.ts",
|
|
44
|
+
"dist/**/*.js"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
40
47
|
"scripts": {
|
|
41
48
|
"build": "cp ../../LICENSE . && tsc -p tsconfig.build.json && vite build",
|
|
42
49
|
"typecheck": "tsc && tsc -p tsconfig.build.json",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Render targets and views
|
|
2
|
+
|
|
3
|
+
A *render target* is an entity with [`Target.options`](01-targets.ts#L8), what its textures are, and `Target.size`, in
|
|
4
|
+
pixels. The options are its color format, its samples per pixel, its depth format and the color it's cleared to each
|
|
5
|
+
frame; `Target.Options.default` has one sample and a depth buffer. With a device, `Target.states` holds its textures.
|
|
6
|
+
|
|
7
|
+
A *view* is an entity drawing into part of a target: `View.target` names the target, `View.viewport` its rectangle in
|
|
8
|
+
it, as fractions of its size, and `View.projection` the matrix taking its scene to clip space.
|
|
9
|
+
[Two views](01-targets.ts#L9-L10) split the screen in halves.
|
|
10
|
+
|
|
11
|
+
- **Owned:** `View.target` is an owner reference, so [despawning the target](01-targets.ts#L27) takes its views with it.
|
|
12
|
+
- **Shaders:** `View.wgsl(1)` gives the WGSL declaring a view's uniform at bind group 1, as `view.projection` and
|
|
13
|
+
`view.size`, which `View.layout(device)` describes.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
import { Entity, Mat4x4, System, World } from "@adobe/ecs";
|
|
3
|
+
import { Target, View } from "../index.js";
|
|
4
|
+
|
|
5
|
+
let screen = Entity.none;
|
|
6
|
+
|
|
7
|
+
const spawnScreen = System.create(({ commands }) => {
|
|
8
|
+
screen = commands.spawn([Target.options, Target.size])({ [Target.options]: { ...Target.Options.default, sampleCount: 4 }, [Target.size]: [800, 600] });
|
|
9
|
+
commands.spawn([View.target, View.viewport, View.projection])({ [View.target]: screen, [View.viewport]: [0, 0, 0.5, 1], [View.projection]: Mat4x4.identity });
|
|
10
|
+
commands.spawn([View.target, View.viewport, View.projection])({ [View.target]: screen, [View.viewport]: [0.5, 0, 0.5, 1], [View.projection]: Mat4x4.identity });
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const listTargets = System.create({ readonly: true, components: { with: [Target.options, Target.size] } }, row => {
|
|
14
|
+
console.log("target", row[Target.size], "samples", row[Target.options].sampleCount);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const listViews = System.create({ readonly: true, components: { with: [View.target, View.viewport] } }, row => {
|
|
18
|
+
console.log("view of", row[View.target] === screen ? "screen" : "another", "at", row[View.viewport]);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
let views = 0;
|
|
22
|
+
const countViews = System.create({ readonly: true, components: { with: [View.target] } }, () => {
|
|
23
|
+
views += 1;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const removeScreen = System.create(({ commands }) => {
|
|
27
|
+
commands.despawn(screen);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export const main = async (): Promise<void> => {
|
|
31
|
+
await using world = World.create();
|
|
32
|
+
await world.run(spawnScreen);
|
|
33
|
+
await world.run(listTargets);
|
|
34
|
+
await world.run(listViews);
|
|
35
|
+
console.log(View.wgsl(1).split("\n")[1]);
|
|
36
|
+
// Its views go with it: each view's target owns it.
|
|
37
|
+
await world.run(removeScreen);
|
|
38
|
+
await world.run(countViews);
|
|
39
|
+
console.log("views left after the screen went:", views);
|
|
40
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Devices, surfaces and frames
|
|
2
|
+
|
|
3
|
+
`Device.request()` gives a WebGPU device, or null where there's none, and a world drawing with it takes it as
|
|
4
|
+
[`gpuDevice`](02-frames.ts#L20-L21). `Device.keep(world)` sets it and asks again each time it's lost.
|
|
5
|
+
|
|
6
|
+
- **Surfaces:** `Surface.attach` makes a render target presenting to a canvas, an `OffscreenCanvas`, so the world may
|
|
7
|
+
run on a worker. [Here](02-frames.ts#L26-L27) it takes the page's canvas; `Surface.observe` keeps the target the
|
|
8
|
+
canvas's size on the page, in device pixels.
|
|
9
|
+
- **Frames:** `Frame.systems` brings targets, surfaces and views up to date with the device and clears each target, then
|
|
10
|
+
presents each surface. A frame runs them with its draws between, which declare
|
|
11
|
+
[`after: [Frame.update], before: [Frame.present]`](02-frames.ts#L6-L8).
|
|
12
|
+
- **Passes:** `View.begin(encoder, view)` begins a pass drawing into a view, limited to its rectangle.
|
|
13
|
+
|
|
14
|
+
Without a device, as in node, the world runs the same systems and draws nothing: a frame still updates
|
|
15
|
+
`View.states`, to no views.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
import { gpuDevice, Mat4x4, System, World } from "@adobe/ecs";
|
|
3
|
+
import { Device, Frame, Surface, Target, View } from "../index.js";
|
|
4
|
+
|
|
5
|
+
// Draws each view: a pass loading what its target holds, limited to the view's rectangle.
|
|
6
|
+
const draw = System.render({ shader: { accessors: {} }, after: [Frame.update], before: [Frame.present] }, ({ encoder }, { resources }) => {
|
|
7
|
+
for (const view of resources[View.states]?.values() ?? []) View.begin(encoder, view).end();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const frame = System.create({ systems: [Frame.systems, draw] });
|
|
11
|
+
|
|
12
|
+
const spawnView = System.create({ components: { with: [Target.size] } }, (row, { commands }) => {
|
|
13
|
+
commands.spawn([View.target, View.viewport, View.projection])({ [View.target]: row.entity, [View.viewport]: [0, 0, 1, 1], [View.projection]: Mat4x4.identity });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const updated = System.create({ readonly: true }, ({ resources }) => resources[View.states] !== null);
|
|
17
|
+
|
|
18
|
+
export const main = async (): Promise<void> => {
|
|
19
|
+
// Null where there's no WebGPU, as in node: the world then draws nothing, and runs the same systems.
|
|
20
|
+
const device = await Device.request();
|
|
21
|
+
const world = World.create({ [gpuDevice]: device });
|
|
22
|
+
// The guide's Output tab has an element #output; elsewhere, as in node, there's none.
|
|
23
|
+
const output = globalThis.document?.querySelector<HTMLElement>("#output") ?? null;
|
|
24
|
+
const canvas = output?.appendChild(document.createElement("canvas")) ?? null;
|
|
25
|
+
if (canvas !== null) {
|
|
26
|
+
const surface = await world.run(Surface.attach, { canvas: canvas.transferControlToOffscreen(), width: canvas.clientWidth, height: canvas.clientHeight, target: { ...Target.Options.default, clear: [0.1, 0.3, 0.6, 1] } });
|
|
27
|
+
Surface.observe(canvas, world, surface);
|
|
28
|
+
await world.run(spawnView);
|
|
29
|
+
}
|
|
30
|
+
console.log("views updated before a frame", await world.run(updated));
|
|
31
|
+
for (let frames = 0; frames < 3; frames++) await world.run(frame);
|
|
32
|
+
console.log("views updated after a frame", await world.run(updated));
|
|
33
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Guide
|
|
2
|
+
|
|
3
|
+
How to draw with `@adobe/ecs-gpu`, in chapters, each its prose, `NN-name.md`, and a program, `NN-name.ts`, whose output
|
|
4
|
+
is `NN-name.out`. The [interactive guide](../../../ecs-guide) shows them after the ECS's own chapters.
|
|
5
|
+
|
|
6
|
+
1. [Render targets and views](01-targets.md)
|
|
7
|
+
2. [Devices, surfaces and frames](02-frames.md)
|