-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
150 lines (142 loc) · 7.89 KB
/
Copy pathindex.html
File metadata and controls
150 lines (142 loc) · 7.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TinyWebGPU — a one-file WebGPU framework, with live demos</title>
<meta name="description" content="A tiny WebGPU framework for shader-first work: WGSL
fullscreen shaders, compute passes and GPGPU in one file, no build step. One JS object is
the single source of truth for uniforms and resources — WGSL structs, binding indices and
buffer offsets are generated for you. Live demos and a step-by-step tutorial.">
<link rel="canonical" href="https://lampmaker.github.io/tinywebgpu/">
<meta property="og:type" content="website">
<meta property="og:site_name" content="TinyWebGPU">
<meta property="og:url" content="https://lampmaker.github.io/tinywebgpu/">
<meta property="og:title" content="TinyWebGPU — a one-file WebGPU framework">
<meta property="og:description" content="A tiny WebGPU framework for shader-first work:
WGSL shaders, compute and GPGPU in one file, no build step. One JS object is the single
source of truth for uniforms and resources. Live demos in the browser.">
<meta name="twitter:card" content="summary">
<!-- Loaded first and on purpose not a module: it turns an uncaught error in the
module scripts below — no WebGPU, no adapter, a file that failed to load — into
a banner on the page, because a phone has no console to print it to. -->
<script src="./diag.js"></script>
<style>
:root {
color-scheme: light dark;
--bg: #ffffff; --fg: #1b1b1f; --muted: #5c5c68; --line: #e3e3e8;
--card: #fafafb; --accent: #2f6df6; --warn-bg: #fff6e5; --warn-fg: #7a4b00;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #131317; --fg: #e8e8ec; --muted: #9a9aa6; --line: #2a2a32;
--card: #1a1a20; --accent: #7aa2ff; --warn-bg: #2c2413; --warn-fg: #e8c983;
}
}
* { box-sizing: border-box; }
body {
margin: 0; padding: 3rem 1.25rem 5rem; background: var(--bg); color: var(--fg);
font: 16px/1.6 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
main { max-width: 46rem; margin: 0 auto; }
h1 { font-size: 2rem; margin: 0 0 .25rem; letter-spacing: -.02em; }
.tag { color: var(--muted); margin: 0 0 2rem; }
code {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: .9em; background: var(--card); border: 1px solid var(--line);
border-radius: 4px; padding: .1em .35em;
}
#unsupported {
display: none; background: var(--warn-bg); color: var(--warn-fg);
border: 1px solid color-mix(in srgb, var(--warn-fg) 30%, transparent);
border-radius: 8px; padding: .85rem 1rem; margin-bottom: 2rem;
}
ul { list-style: none; padding: 0; margin: 0; display: grid; gap: .85rem; }
a.demo {
display: block; padding: 1rem 1.15rem; background: var(--card); color: inherit;
border: 1px solid var(--line); border-radius: 10px; text-decoration: none;
transition: border-color .15s ease, transform .15s ease;
}
a.demo:hover { border-color: var(--accent); transform: translateY(-1px); }
a.demo strong { display: block; font-size: 1.05rem; }
a.demo.start {
margin-bottom: 2rem; border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 8%, var(--card));
}
a.demo.start strong { font-size: 1.15rem; }
h2 { font-size: 1rem; margin: 0 0 .8rem; color: var(--muted); font-weight: 600;
text-transform: uppercase; letter-spacing: .05em; }
a.demo span { color: var(--muted); font-size: .92rem; }
footer { margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--line); color: var(--muted); font-size: .92rem; }
footer a { color: var(--accent); }
</style>
</head>
<body>
<main>
<h1>TinyWebGPU</h1>
<p class="tag">One file, no dependencies, no build step. Live demos below — each is a single
self-contained HTML file. The picker in the corner switches every demo between the readable
source, the minified build and the tiny build — the tiny one drops optional features, so
demos that need them will say so.</p>
<a class="demo start" href="docs/tutorial.html">
<strong>Start here · The tutorial</strong>
<span>Sixteen steps from one coloured pixel to a particle system, with a live, editable
code box at every stage. Runs on your GPU as you read.</span></a>
<div id="unsupported">
<strong>WebGPU isn’t available in this browser.</strong> The demos need Chrome/Edge 113+,
Firefox 141+ (Windows), or Safari 26+, over https or localhost. On Android that means
Chrome 121+ on Android 12+ — Samsung Internet, Firefox for Android and the in-app browsers
inside chat and mail apps have no WebGPU at all.
<a href="docs/webgpu-check.html">Run the WebGPU check</a> to see what this device reports.
</div>
<h2>Examples</h2>
<ul>
<li><a class="demo" href="examples/1_hello.html">
<strong>1 · Hello fullscreen shader</strong>
<span>An animated fragment shader in about ten lines.</span></a></li>
<li><a class="demo" href="examples/2_compute_readback.html">
<strong>2 · Compute → storage buffer → readback</strong>
<span>A compute pass with no canvas at all, reading results back to JS.</span></a></li>
<li><a class="demo" href="examples/3_life.html">
<strong>3 · Ping-pong compute + present</strong>
<span>Game of life: two buffers swapped each frame, stepped and drawn in one submit.</span></a></li>
<li><a class="demo" href="examples/4_indirect.html">
<strong>4 · Indirect dispatch with GPU-side counters</strong>
<span>A kernel compacts work and counts it atomically; the next dispatch sizes itself
from that count, with no CPU round-trip.</span></a></li>
<li><a class="demo" href="examples/5_texture.html">
<strong>5 · Textures and blending</strong>
<span>Pixels uploaded from raw bytes and from an image source, sampled in a shader,
with a translucent pass composited on top.</span></a></li>
<li><a class="demo" href="examples/6_evolution.html">
<strong>6 · Differential evolution</strong>
<span>A real black-box optimizer run population-parallel: one thread per individual,
four textbook-hard objectives, and a 2D slice through a 32-dimensional search.</span></a></li>
<li><a class="demo" href="examples/7_particles.html">
<strong>7 · Particle simulator</strong>
<span>Up to 800k particles pulled around by your pointer. No vertex buffers — each one
splats into a density grid, and a fullscreen pass colours it.</span></a></li>
<li><a class="demo" href="examples/8_heightmap.html">
<strong>8 · Flat-shaded height map</strong>
<span>Your own vertex stage: a compute pass writes the terrain, and the vertex shader
reads it straight back out of the same buffer. 32k facets, no vertex buffers, and
<code>depth: true</code> for the hiding.</span></a></li>
</ul>
<footer>
Nothing rendering? <a href="docs/webgpu-check.html">Check WebGPU on this device</a>.<br>
Source and docs: <a href="https://github.com/lampmaker/tinywebgpu">github.com/lampmaker/tinywebgpu</a>
· The <a href="docs/tutorial.html">tutorial</a>, the
<a href="https://github.com/lampmaker/tinywebgpu#readme">README</a> and the
<a href="https://github.com/lampmaker/tinywebgpu/blob/main/docs/API.md">API reference</a>. MIT licensed.
</footer>
</main>
<script>
if (!navigator.gpu) document.getElementById('unsupported').style.display = 'block';
</script>
<script type="module">
// The build picker: draws the corner control and carries ?lib= into every demo link.
import { initPicker } from './libselect.js';
initPicker();
</script>
</body>
</html>