wgpu-kit 0.9.10

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) 2026 wgpu-kit authors
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 ADDED
@@ -0,0 +1,96 @@
1
+ # wgpu-kit
2
+
3
+ **Browser GPGPU middle layer. 200,000 particles at 142fps — in 5 lines of code.**
4
+ All the WebGPU boilerplate — device, buffers, pipelines, dispatch, readbacks — wrapped into two simple API layers.
5
+
6
+ [**API Reference**](docs/API.md) · [中文文档](README.zh-CN.md) · **[LIVE DEMO](https://nanfengw0w.github.io/wgpu-kit/)** · Changelog: [releases](https://github.com/nanfengw0w/wgpu-kit/releases)
7
+
8
+ ![wgpu-kit particle life](docs/assets/hero.gif)
9
+
10
+ ## Quick start
11
+
12
+ ```bash
13
+ npm i wgpu-kit
14
+ ```
15
+
16
+ **100,000 particles in 5 lines:**
17
+
18
+ ```ts
19
+ import { particles } from 'wgpu-kit';
20
+
21
+ const sim = await particles({ count: 100_000, forces: 'cells' });
22
+ await sim.attach(canvas);
23
+ function frame() { sim.tick(); requestAnimationFrame(frame); }
24
+ frame();
25
+ ```
26
+
27
+ **Custom GPU compute** — you only write the per-element function:
28
+
29
+ ```ts
30
+ import { elementKernel, Buffer } from 'wgpu-kit';
31
+
32
+ const pos = await Buffer.create('vec2f', 100_000);
33
+ const vel = await Buffer.create('vec2f', 100_000);
34
+
35
+ const integrate = elementKernel({
36
+ state: { pos: 'vec2f' },
37
+ inputs: { vel: 'vec2f' },
38
+ uniforms: { dt: 'f32' },
39
+ code: `
40
+ fn userFn(idx: u32, dt: f32) {
41
+ pos[idx] = (pos[idx] + vel[idx] * dt) * 0.99;
42
+ }
43
+ `,
44
+ });
45
+ await integrate.run({ pos, vel }, { dt: 0.02 });
46
+ ```
47
+
48
+ Device management, buffer sizing, pipeline creation, double buffering,
49
+ dispatch, readbacks, error line-mapping — all handled by the library.
50
+
51
+ ## Entry points
52
+
53
+ | import | purpose |
54
+ | --- | --- |
55
+ | `wgpu-kit` | elementKernel core + Buffer / PingPong / rawKernel |
56
+ | `wgpu-kit/particles` | particle life: presets, adaptive world, live updates |
57
+ | `wgpu-kit/life` | Turing patterns / Physarum / Boids / Tentacles |
58
+ | `wgpu-kit/fields` | vector-field advection trails |
59
+ | `wgpu-kit/image` | GPU filter pipeline (blur/sharpen/edge/…) |
60
+ | `wgpu-kit/react` | `<ParticleCanvas />` |
61
+ | `wgpu-kit/three` | three.js snapshot interop |
62
+ | `wgpu-kit/media` | canvas recording (webm/mp4) |
63
+ | `wgpu-kit/vite` | WGSL kernel hot reload |
64
+
65
+ ![life quartet](docs/assets/life-quartet.png)
66
+
67
+ *The life pack: Turing patterns / Physarum / Boids / Tentacles — [open the demo](https://nanfengw0w.github.io/wgpu-kit/life.html).*
68
+
69
+ ## Numbers (reproducible)
70
+
71
+ | metric | value | environment |
72
+ | --- | --- | --- |
73
+ | particles end-to-end | 200,000 @ 142fps | RTX 4060 Laptop, playground |
74
+ | particle compute (grid) | 131k @ 0.89ms/frame | headless bench |
75
+ | neighborhood algorithms | grid ~O(N); 8.5× faster than brute force at 66k | same-session A/B |
76
+ | bundle size | core gzip 5.5kB; +particles 10.3kB | gzip |
77
+
78
+ ## Three design rules
79
+
80
+ 1. **Level-2 works in 5 minutes, level-1 has no ceiling** — `rawKernel` and
81
+ native `GPUBuffer` escape hatches stay open;
82
+ 2. **Errors speak human** — WGSL compile failures map back to your line numbers;
83
+ 3. **Benchmarks are documentation** — every published number is reproducible;
84
+ gzip budgets are enforced by `npm run build`.
85
+
86
+ ## Support matrix
87
+
88
+ | browser | status |
89
+ | --- | --- |
90
+ | Chrome / Edge 113+ (incl. headless) | ✅ all validation runs here (RTX 4060, D3D backend) |
91
+ | Safari 18+ / Firefox | 🔶 should work with WebGPU enabled; untested — issues welcome |
92
+ | WebGL2 / no WebGPU | ❌ no fallback (by design); `detect.html` can diagnose |
93
+
94
+ ## License
95
+
96
+ [MIT](LICENSE)
@@ -0,0 +1,99 @@
1
+ # wgpu-kit
2
+
3
+ > **Browser GPGPU middle layer. 132,000 particles at 142fps — in 5 lines of code.**
4
+ > 浏览器 GPGPU 中间层:WebGPU 计算的全套样板,打包成两层简单 API。
5
+
6
+ **状态:公测就绪(v0.9.5)· 演示:[playground](playground/index.html) · [生命合集](playground/life.html) · [画廊](playground/gallery.html)**
7
+ · **[API 参考(学习文档)](docs/API.md)** · **[文件结构](docs/STRUCTURE.md)** · [基准](docs/benchmarks.md) · API 设计 · 验证日志 · 路线图 · [CHANGELOG](CHANGELOG.md)
8
+
9
+ ## Quick start
10
+
11
+ ```bash
12
+ npm i wgpu-kit # 首次发布前:git clone + npm run build
13
+ ```
14
+
15
+ **5 行,10 万粒子**(领域包,开箱即用):
16
+
17
+ ```ts
18
+ import { particles } from 'wgpu-kit';
19
+
20
+ const sim = await particles({ count: 100_000, forces: 'cells' });
21
+ await sim.attach(canvas);
22
+ function frame() { sim.tick(); requestAnimationFrame(frame); }
23
+ frame();
24
+ ```
25
+
26
+ **自定义 GPU 计算**(kernel 核心,写"单个元素怎么变"就行):
27
+
28
+ ```ts
29
+ import { elementKernel, Buffer } from 'wgpu-kit';
30
+
31
+ const pos = await Buffer.create('vec2f', 100_000);
32
+ const vel = await Buffer.create('vec2f', 100_000);
33
+
34
+ const integrate = elementKernel({
35
+ state: { pos: 'vec2f' },
36
+ inputs: { vel: 'vec2f' },
37
+ uniforms: { dt: 'f32' },
38
+ code: `
39
+ fn userFn(idx: u32, dt: f32) {
40
+ pos[idx] = (pos[idx] + vel[idx] * dt) * 0.99;
41
+ }
42
+ `,
43
+ });
44
+ await integrate.run({ pos, vel }, { dt: 0.02 });
45
+ ```
46
+
47
+ 设备/缓冲/管线/绑定/dispatch/双缓冲/读回/错误行号映射——全部由库承担。
48
+
49
+ ## 包家族
50
+
51
+ | 入口 | 一句话 |
52
+ | --- | --- |
53
+ | `wgpu-kit` | elementKernel 核心 + Buffer/PingPong/rawKernel |
54
+ | `wgpu-kit/particles` | 粒子生命:力矩阵预设/随机宇宙、grid 邻域、热更新、快照分享 |
55
+ | `wgpu-kit/life` | 人工生命:图灵斑图 / 粘菌 / Boids / 软体触手 |
56
+ | `wgpu-kit/fields` | 向量场平迹(数据可视化) |
57
+ | `wgpu-kit/image` | GPU 滤镜管线(blur/sharpen/edge/…) |
58
+ | `wgpu-kit/react` | `<ParticleCanvas />` |
59
+ | `wgpu-kit/three` | three.js 快照互通 |
60
+ | `wgpu-kit/media` | 画布录制(一键产视频素材) |
61
+ | `wgpu-kit/vite` | kernel 热重载插件(WGSL 改动毫秒级生效) |
62
+
63
+ ## 数字(可复现,非营销)
64
+
65
+ | 指标 | 数值 | 环境 |
66
+ | --- | --- | --- |
67
+ | 粒子模拟(端到端) | **131,072 粒子 @ 142fps** | RTX 4060 Laptop,playground 实测 |
68
+ | 粒子计算(纯 GPU) | grid@131k = **0.89 ms/帧** | 同上,headless 基准 |
69
+ | 邻域算法对比 | grid 比 O(N²) tiling 快 **6.7×**@16k,近似 O(N) | 同会话基准 |
70
+ | 库体积 | core gzip **5.34 kB**;+particles **10.27 kB** | gzip -c |
71
+
72
+ 完整数据与复现命令:开发仓库 benchmarks.md。基准方法学(含两次自我纠错)见验证日志 05。
73
+
74
+ ## 为什么
75
+
76
+ 浏览器里用 GPU,今天只有四条路:纯 JS(慢)、裸写 WebGPU(~150 行仪式代码)、three.js TSL(锁引擎)、gpu.js(WebGL 时代,停滞)。"**简单 + 快 + 引擎无关**"的专用 WebGPU 计算库是空位。完整竞品分析:docs/research.md。
77
+
78
+ ## 三条设计铁律
79
+
80
+ 1. **第二层 5 分钟出活,第一层不封顶**——`rawKernel` 与原生 `GPUBuffer` 逃生舱常开;
81
+ 2. **错误说人话**——WGSL 编译失败精确映射回你的代码行;
82
+ 3. **基准即文档**——所有宣传数字可复现,性能预算进 CI(`npm run build` 自动核对体积)。
83
+
84
+ ## 支持矩阵
85
+
86
+ | 浏览器 | 状态 |
87
+ | --- | --- |
88
+ | Chrome / Edge 113+(含无头) | ✅ 本项目全部验证在此完成(RTX 4060,D3D 后端) |
89
+ | Safari 18+ | 🔶 WebGPU 可用即应工作;未在本项目环境实测,issue 欢迎 |
90
+ | Firefox | 🔶 同上 |
91
+ | WebGL2 / 无 WebGPU | ❌ 不做降级(ADR-1);打开 [detect 页](playground/detect.html)可诊断 |
92
+
93
+ ## 项目方法论
94
+
95
+ 这不是一个"写完就算"的仓库:**每个阶段完成后,由无头浏览器在真实 GPU 上运行结构化探针验证,验证日志、路径对比、事故复盘全部入档**。从裸 WebGPU spike 到 13 万粒子,共 6 个阶段、7 个版本标签、38 项自动化探针。
96
+
97
+ ## 许可
98
+
99
+ [MIT](LICENSE)
@@ -0,0 +1,21 @@
1
+ import { type ScalarKind } from './layout.ts';
2
+ /** TS 5.7+ 的 TypedArray 泛型:显式钉在 ArrayBuffer 上,兼容 WebGPU 的 GPUAllowSharedBufferSource */
3
+ export type NumArray = Float32Array<ArrayBuffer> | Int32Array<ArrayBuffer> | Uint32Array<ArrayBuffer>;
4
+ /**
5
+ * 显存数组的类型化封装。替用户做三件事:
6
+ * ① 算字节数与 usage;② write() 校验长度;③ read() 内置 staging buffer(mapAsync 陷阱全包掉)。
7
+ * `gpuBuffer` 原生句柄永远可取(章程原则 1:逃生舱常开)。
8
+ */
9
+ export declare class Buffer<K extends ScalarKind = ScalarKind> {
10
+ #private;
11
+ readonly kind: K;
12
+ readonly length: number;
13
+ readonly gpuBuffer: GPUBuffer;
14
+ private constructor();
15
+ static create<K extends ScalarKind>(kind: K, length: number): Promise<Buffer<K>>;
16
+ /** 校验并写入(CPU → GPU) */
17
+ write(data: NumArray): void;
18
+ /** GPU → CPU:内部 staging buffer + mapAsync,mapAsync 的异步陷阱由库承担 */
19
+ read(): Promise<NumArray>;
20
+ destroy(): void;
21
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 设备上下文:全库单例,惰性申请 adapter/device。
3
+ * 峰值性能偏好;失败给人话报错;device lost 以 promise 形式暴露。
4
+ */
5
+ export declare class GpuContext {
6
+ #private;
7
+ readonly device: GPUDevice;
8
+ readonly adapterInfo: string;
9
+ private constructor();
10
+ static get(): Promise<GpuContext>;
11
+ /** device lost 时 reject;调用方可 await 做清理/提示 */
12
+ get lost(): Promise<GPUDeviceLostInfo>;
13
+ /** 等待队列中已提交的全部 GPU 工作完成(测试/读回前同步用) */
14
+ sync(): Promise<void>;
15
+ }
@@ -0,0 +1,20 @@
1
+ /** 错误体系:所有错误说人话,给出定位与修复建议(章程原则 3)。 */
2
+ export declare class WgpuKitError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /** 环境无 WebGPU / 拿不到 adapter。 */
6
+ export declare class WebGPUUnavailableError extends WgpuKitError {
7
+ constructor(reason: string);
8
+ }
9
+ /** WGSL 编译错误,行号已映射回用户代码。 */
10
+ export declare class CompileError extends WgpuKitError {
11
+ constructor(kernelName: string, messages: readonly {
12
+ line: number;
13
+ msg: string;
14
+ }[], userCodeOffset: number);
15
+ }
16
+ /** 调用方使用不当(缺资源/类型不匹配/长度不一致等)。 */
17
+ export declare class UsageError extends WgpuKitError {
18
+ }
19
+ /** 创建 compute 管线并用 pushErrorScope 捕获异步校验错误(超限等),把"黑屏刷屏"变成显式报错 */
20
+ export declare function createComputePipelineChecked(device: GPUDevice, module: GPUShaderModule, label: string, entryPoint?: string): Promise<GPUComputePipeline>;
@@ -0,0 +1,52 @@
1
+ import { type ScalarKind, type UniformLayout } from './layout.ts';
2
+ import { Buffer } from './buffer.ts';
3
+ /**
4
+ * elementKernel —— wgpu-kit 的心脏。
5
+ *
6
+ * 用户只写"单个元素怎么变"的 WGSL 函数(第一个参数固定为 idx: u32,
7
+ * 之后按 uniforms 声明顺序接收 uniform 标量),库生成全部仪式:
8
+ * uniform struct + 对齐打包、storage 绑定、count 越界保护、
9
+ * workgroup/dispatch、bind group 缓存、编译错误行号映射回用户代码。
10
+ */
11
+ export interface ElementKernelSpec {
12
+ /** 调试名,错误信息里出现 */
13
+ name?: string;
14
+ /** 读写字段(就地修改),如 { pos: 'vec2f' } */
15
+ state?: Record<string, ScalarKind>;
16
+ /** 只读字段,如 { vel: 'vec2f' } */
17
+ inputs?: Record<string, ScalarKind>;
18
+ /** uniform 标量(不允许叫 count,count 由库自动注入) */
19
+ uniforms?: Record<string, ScalarKind>;
20
+ /** workgroup 大小,默认 64 */
21
+ workgroupSize?: number;
22
+ /** 用户函数,如 `fn step(idx: u32, dt: f32) { ... }`(引用字段名直接访问数组) */
23
+ code: string;
24
+ }
25
+ export interface ElementKernel {
26
+ readonly name: string;
27
+ /** 生成的完整 WGSL(调试/单测用) */
28
+ readonly source: string;
29
+ readonly uniformLayout: UniformLayout;
30
+ readonly workgroupSize: number;
31
+ run(resources: Record<string, Buffer>, uniforms?: Record<string, number>): Promise<void>;
32
+ /** 热重载:替换用户函数并重建管线;编译失败时抛错且内核保持旧版 */
33
+ replace(code: string): Promise<void>;
34
+ destroy(): void;
35
+ }
36
+ interface NormalizedSpec {
37
+ name: string;
38
+ workgroupSize: number;
39
+ state: Array<readonly [string, ScalarKind]>;
40
+ inputs: Array<readonly [string, ScalarKind]>;
41
+ uniforms: Array<readonly [string, ScalarKind]>;
42
+ code: string;
43
+ }
44
+ /** 纯函数:规范校验 + WGSL 代码生成。单测直接覆盖,不碰 GPU。 */
45
+ export declare function generateElementKernel(spec: ElementKernelSpec): {
46
+ normalized: NormalizedSpec;
47
+ source: string;
48
+ uniformLayout: UniformLayout;
49
+ userCodeLineOffset: number;
50
+ };
51
+ export declare function elementKernel(spec: ElementKernelSpec): ElementKernel;
52
+ export {};
@@ -0,0 +1,32 @@
1
+ /** WGSL 类型布局表:尺寸、对齐、组件数、对应的 TypedArray。库替用户算字节数的根据。 */
2
+ export type ScalarKind = 'f32' | 'i32' | 'u32' | 'vec2f' | 'vec2i' | 'vec2u' | 'vec3f' | 'vec4f';
3
+ export interface TypeDef {
4
+ /** 字节数 */
5
+ readonly size: number;
6
+ /** 字节对齐(WGSL 规则:vec3 对齐到 16) */
7
+ readonly align: number;
8
+ /** 分量数 */
9
+ readonly comps: number;
10
+ readonly typed: 'Float32Array' | 'Int32Array' | 'Uint32Array';
11
+ readonly wgsl: string;
12
+ }
13
+ export declare const TYPES: Record<ScalarKind, TypeDef>;
14
+ export declare function alignTo(offset: number, align: number): number;
15
+ export interface UniformField {
16
+ readonly name: string;
17
+ readonly kind: ScalarKind;
18
+ /** 在 uniform struct 中的字节偏移(与 WGSL 自然对齐规则一致) */
19
+ readonly offset: number;
20
+ }
21
+ export interface UniformLayout {
22
+ readonly fields: readonly UniformField[];
23
+ /** 总字节数,向上取整到 16 的倍数(uniform 绑定安全尺寸) */
24
+ readonly size: number;
25
+ }
26
+ /**
27
+ * 按声明顺序规划 uniform 布局。声明顺序 = WGSL struct 成员顺序 = 用户函数参数顺序,
28
+ * 三者由库保证一致,不给用户对齐自由(对齐是库的事)。
29
+ */
30
+ export declare function planUniform(entries: ReadonlyArray<readonly [string, ScalarKind]>): UniformLayout;
31
+ /** 把标量值按布局写进 ArrayBuffer;缺失字段报错,多余字段忽略前给出字段清单便于排错 */
32
+ export declare function packUniform(layout: UniformLayout, values: Readonly<Record<string, number>>): ArrayBuffer;
@@ -0,0 +1,24 @@
1
+ import { Buffer } from './buffer.ts';
2
+ import { type ScalarKind } from './layout.ts';
3
+ /**
4
+ * 双缓冲:模拟类 kernel 的绝对刚需(spike 中是 45 行仪式)。
5
+ * A/B 两组同构缓冲,读"当前侧"、写"另一侧",swap 一次完成帧间翻转。
6
+ * 泛型 K 保留字段名的字面量类型,Record 访问不会被 noUncheckedIndexedAccess 弄成 undefined。
7
+ */
8
+ export declare class PingPong<K extends string> {
9
+ #private;
10
+ private constructor();
11
+ static create<K extends string>(kinds: Record<K, ScalarKind>, length: number): Promise<PingPong<K>>;
12
+ /** 当前帧的数据侧(渲染/读回用) */
13
+ get current(): Record<K, Buffer>;
14
+ /** 另一侧(kernel 写入目标) */
15
+ get other(): Record<K, Buffer>;
16
+ /** 帧末翻转 */
17
+ swap(): void;
18
+ /** 以 (写侧, 读侧) 调用 fn 后自动 swap 的语法糖 */
19
+ runWith(fn: (write: Record<K, Buffer>, read: Record<K, Buffer>) => Promise<void>): Promise<void>;
20
+ destroy(): void;
21
+ /** 克隆一份同构 PingPong(同字段同长度) */
22
+ clone(): Promise<PingPong<K>>;
23
+ get names(): readonly K[];
24
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * rawKernel —— 逃生舱(章程原则 1)。
3
+ * 用户给完整 WGSL(自己写 binding 声明),库只负责管线与提交,不做任何加工。
4
+ */
5
+ export interface RawKernel {
6
+ run(entries: GPUBindGroupEntry[], workgroups: number): Promise<void>;
7
+ destroy(): void;
8
+ }
9
+ export declare function rawKernel(code: string, entryPoint?: string, label?: string): RawKernel;