@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 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
- var perDevice = (create, keyOf = (key) => JSON.stringify(key)) => {
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
- var request = async (options = {}) => {
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
- var set = System.create({}, ({ resources }, input) => {
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
- var keep = async (world, options = {}) => {
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
- var Options$1 = { default: {
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
- var options$1 = Symbol("Target.options");
109
+ const options$1 = Symbol("Target.options");
110
110
  declare$$2(options$1, "component", { default: Options$1.default });
111
- var size = Symbol("Target.size");
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
- var states$2 = Symbol("Target.states");
123
+ const states$2 = Symbol("Target.states");
124
124
  declare$$2(states$2, "resource", {});
125
- var 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
- var destroyTextures = (state) => {
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
- var created = (device, entity, declared, [width, height]) => {
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
- var updated$2 = (device, previous, targets) => {
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
- var recordClears = (encoder, targets) => {
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
- var release$2 = Finalizer.create({ components: { with: [options$1, size] } }, (target, { resources }) => {
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
- var resize = System.create({
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
- var Options = { default: {
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
- var canvas = Symbol("Surface.canvas");
268
+ const canvas = Symbol("Surface.canvas");
269
269
  declare$$1(canvas, "component", { transfer: true });
270
- var options = Symbol("Surface.options");
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
- var states$1 = Symbol("Surface.states");
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
- var attach = System.create({}, ({ commands }, input) => commands.spawn([
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
- var sameOptions = (a, b) => a.alphaMode === b.alphaMode && a.colorSpace === b.colorSpace && a.toneMapping === b.toneMapping;
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
- var updated$1 = (device, targets, previous, surfaces) => {
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
- var release$1 = Finalizer.create({ components: { with: [canvas] } }, (surface, { resources }) => {
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
- var pixelsOf = (entry) => {
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
- var observe = (element, world, surface) => {
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
- var target = Symbol("View.target");
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
- var viewport = Symbol("View.viewport");
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
- var projection = Symbol("View.projection");
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
- var states = Symbol("View.states");
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
- var uniformBytes = 80;
467
- var layouts = perDevice((device, _key) => device.createBindGroupLayout({
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
- var layout = (device) => layouts(device, null);
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
- var wgsl = (group) => `struct View { projection: mat4x4f, size: vec2f }\n@group(${group}) @binding(0) var<uniform> view: View;\n`;
479
- var rectangleOf = ([x, y, width, height], [targetWidth, targetHeight]) => {
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
- var sameRectangle = (a, b) => a.every((value, index) => value === b[index]);
490
- var sameMatrix = (a, b) => a.every((value, index) => value === b[index]);
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
- var updated = (device, targets, previous, views) => {
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
- var release = Finalizer.create({ components: { with: [
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
- var begin = (encoder, view, label) => {
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
- var everyTarget = Index.create({
592
+ const everyTarget = Index.create({
593
593
  key: [],
594
594
  components: { with: [options$1, size] }
595
595
  });
596
- var everySurface = Index.create({
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
- var everyView = Index.create({
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
- var update = System.create({ lookup: {
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
- var present = System.render({
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
- var systems = System.create({ systems: [update, present] });
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.1",
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.1"
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,5 @@
1
+ target [ 800, 600 ] samples 4
2
+ view of screen at [ 0, 0, 0.5, 1 ]
3
+ view of screen at [ 0.5, 0, 0.5, 1 ]
4
+ @group(1) @binding(0) var<uniform> view: View;
5
+ views left after the screen went: 0
@@ -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,2 @@
1
+ views updated before a frame false
2
+ views updated after a frame true
@@ -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)