@adobe/ecs-gpu 0.0.0-stage → 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 Adobe, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,111 @@
1
- # Temporary Holding Version
1
+ # @adobe/ecs-gpu
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ WebGPU for `@adobe/ecs`: the device a world draws with, the canvases it presents to, the textures it draws into, the
4
+ views it draws, and the systems that keep them current. Everything is an entity, a component, a resource or a system
5
+ of the world, so the world's thread may be the page's or a worker's, and a world may have any number of canvases,
6
+ render targets and views, or none.
7
+
8
+ It adds no frame loop: the world's own runs and ticks drive it.
9
+
10
+ ## A frame
11
+
12
+ ```ts
13
+ import { System, World } from "@adobe/ecs";
14
+ import { Device, Frame, Surface, View } from "@adobe/ecs-gpu";
15
+
16
+ const world = World.create();
17
+ await Device.keep(world);
18
+
19
+ const canvas = document.querySelector("canvas")!;
20
+ const surface = await world.run(Surface.attach, {
21
+ canvas: canvas.transferControlToOffscreen(),
22
+ width: canvas.clientWidth * devicePixelRatio,
23
+ height: canvas.clientHeight * devicePixelRatio,
24
+ });
25
+ Surface.observe(canvas, world, surface);
26
+
27
+ // Draws go after Frame.update and before Frame.present.
28
+ const draw = System.render({ shader, after: [Frame.update], before: [Frame.present] }, ({ device, encoder, tables }, { resources }) => {
29
+ for (const view of resources[View.states]?.values() ?? []) {
30
+ const pass = View.begin(encoder, view);
31
+ // set a pipeline, bind view.bindGroup, bind and draw each table
32
+ pass.end();
33
+ }
34
+ });
35
+
36
+ world.add(System.create({ systems: [Frame.systems, draw] }));
37
+ ```
38
+
39
+ ## Devices
40
+
41
+ - `Device.request(options?)` gives a device for the adapter's options and the features and limits it needs, or null
42
+ where there's no WebGPU or no such device.
43
+ - `Device.keep(world, options?)` sets the world's `gpuDevice` and requests another each time it's lost.
44
+ - `Device.set` is the system that sets `gpuDevice`.
45
+
46
+ Call them on the world's thread, since a device can't move between threads. When the device changes, or is lost and
47
+ the world sets `gpuDevice` to null, every target, surface and view is made again on the new device, or released.
48
+
49
+ ## Render targets
50
+
51
+ An entity with `Target.options` and `Target.size` is a render target.
52
+
53
+ - **Options:**
54
+ - its color format, null for the platform's preferred canvas format;
55
+ - its samples per pixel, 1 or 4;
56
+ - its depth format, null for none;
57
+ - the color it's cleared to each frame, null to keep what it holds.
58
+ - **Textures:** `Target.states` holds each target's textures on the world's device. `color` is single-sampled, for
59
+ reading and presenting. With 4 samples, passes draw into `multisampled` and resolve into `color`. Depth textures can
60
+ be sampled.
61
+ - **Resizing:** `Target.resize` sets a target's size in pixels.
62
+
63
+ A target without a canvas renders offscreen: for a texture a later pass samples, a picking buffer or a screenshot.
64
+
65
+ ## Surfaces
66
+
67
+ A render target with `Surface.canvas` presents to an `OffscreenCanvas` on the world's thread.
68
+
69
+ - **Canvas:** a page's canvas moved with `transferControlToOffscreen()`, or an `OffscreenCanvas` of its own.
70
+ `Surface.attach` spawns one.
71
+ - **Presenting:** `Surface.options` sets its alpha mode, color space and tone mapping. The canvas is configured in its
72
+ target's format and always has its target's size.
73
+ - **Resizing:** `Surface.observe(element, world, surface)`, on the page's thread, keeps a surface's size the element's
74
+ size in device pixels. It works whether the world is on the page's thread or on a worker that the page joined.
75
+
76
+ Draws go into the target's textures, and `Frame.present` copies each surface's target into its canvas in one body. So
77
+ every draw of a run is in the frame the browser shows, even where the run waited between draws, as a readback makes it
78
+ wait. That costs one copy of each surface per frame.
79
+
80
+ ## Views
81
+
82
+ An entity with `View.target`, `View.viewport` and `View.projection` is a view.
83
+
84
+ - **Target:** the target it draws into, which owns it, so a view goes when its target goes.
85
+ - **Viewport:** its rectangle in that target, as fractions of the target's size.
86
+ - **Projection:** the matrix taking its scene to clip space, which a system of the application writes before
87
+ `Frame.update`.
88
+
89
+ `View.states` holds each view's rectangle in pixels and the uniform buffer and bind group holding its projection and
90
+ size. Shaders declare them with `View.wgsl(group)`, as `view.projection` and `view.size`, and pipeline layouts take
91
+ `View.layout(device)` at that group. `View.begin(encoder, view)` begins a pass drawing into the view: it loads what the
92
+ target holds and limits the pass to the view's rectangle.
93
+
94
+ ## Frames
95
+
96
+ - **`Frame.update`:** brings targets, surfaces and views up to date with their entities and the world's device, then
97
+ clears each target that declares a clear color.
98
+ - **`Frame.present`:** presents every surface.
99
+ - **`Frame.systems`:** both, in order.
100
+
101
+ Render systems drawing into targets go after `Frame.update` and before `Frame.present`.
102
+
103
+ ## Caches
104
+
105
+ `Cache.perDevice(create, keyOf?)` makes a value once per device and key: a pipeline for a target's format and sample
106
+ count, a layout, a sampler. A device that was replaced or lost takes its values with it.
107
+
108
+ ## Building
109
+
110
+ This is a library of systems. It builds with Vite and `Compiler.plugin({ library: true })`, so its `dist` carries its
111
+ keys' registrations and its systems' input schemas. An application's build, with `Compiler.plugin()`, identifies them.