Skip to content

Commit f4a5f43

Browse files
committed
Merge branch 'release'
2 parents c7cd718 + 34d1537 commit f4a5f43

2 files changed

Lines changed: 331 additions & 0 deletions

File tree

145 KB
Loading
Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
---
2+
title: TypeGPU 0.11
3+
date: 2026-04-14
4+
tags:
5+
- Release notes
6+
authors:
7+
- name: Iwo Plaza
8+
title: TypeGPU developer
9+
picture: https://avatars.githubusercontent.com/u/7166752?s=200
10+
cover:
11+
alt: A collage of examples introduced alongside TypeGPU 0.11
12+
image: banner.webp
13+
---
14+
15+
Hello fellow GPU enthusiast!
16+
17+
Over the past 2 months, my team and I have been pulling on a few threads that we thought would improve TypeGPU in terms of efficiency, and as a byproduct, we actually made the APIs more convenient. We are also introducing a _lint plugin_ to further improve the diagnostics and feedback you receive while writing TypeGPU shaders, on top of the type safety we already provide.
18+
19+
- [New examples](#new-examples)
20+
- [Migration guide](#migration-guide)
21+
- [New and improved write APIs](#new-and-improved-write-apis)
22+
- [Shader code ergonomics](#shader-code-ergonomics)
23+
- [Ecosystem updates](#ecosystem-updates)
24+
- [What's next?](#whats-next)
25+
26+
27+
We have been pulling a few more threads than I mentioned here... but for those, you'll have to wait for the next blog post 🤐.
28+
29+
## New examples
30+
31+
My teammate Konrad Reczko [(@reczkok)](https://github.com/reczkok) has outdone himself again, and delivered 3 new examples that push TypeGPU APIs to their limits:
32+
33+
* ["Genetic Racing"](https://typegpu.com/examples/#example=algorithms--genetic-racing) - watch a swarm of cars learn to traverse a procedurally generated race track.
34+
* ["Mesh Skinning"](https://typegpu.com/examples/#example=simple--mesh-skinning) - an animation and skinning system built from scratch in TypeGPU.
35+
* ["Parallax Occlusion Mapping"](https://typegpu.com/examples/#example=rendering--pom) - squeezing amazing depth out of just two triangles and a set of textures.
36+
37+
## Migration guide
38+
39+
### Deprecated APIs
40+
41+
The `buffer.writePartial` API is being deprecated in favor of `buffer.patch` [(and here are the reasons why)](#a-better-partial-write).
42+
To migrate, simply replace any partial write of arrays in the form of `[{ idx: 2, value: foo }, /* ... */]` with `{ 2: foo, /* ... */ }`.
43+
44+
```diff lang=ts
45+
const buffer = root.createBuffer(d.arrayOf(d.vec3f, 5)).$usage('storage');
46+
47+
- buffer.writePartial([{ idx: 2, value: d.vec3f(1, 2, 3) }]);
48+
+ buffer.patch({ 2: d.vec3f(1, 2, 3) });
49+
```
50+
51+
### Stabilizing textures and samplers
52+
53+
One by one, we're making our APIs available without the `['~unstable']` prefix, and this time around, it's **textures** and **samplers**.
54+
Just drop the unstable prefix, and you're good to go.
55+
56+
```diff lang=ts
57+
- const sampler = root['~unstable'].createSampler({
58+
+ const sampler = root.createSampler({
59+
magFilter: 'linear',
60+
minFilter: 'linear',
61+
});
62+
63+
- const texture = root['~unstable'].createTexture({
64+
+ const texture = root.createTexture({
65+
size: [256, 256],
66+
format: 'rgba8unorm' as const,
67+
}).$usage('sampled');
68+
```
69+
70+
## New and improved write APIs
71+
72+
### Efficient data
73+
74+
When writing to a buffer with an array of vectors, it's no longer required to create vector instances (e.g. `d.vec3f()`).
75+
```ts
76+
const positionsMutable = root.createMutable(d.arrayOf(d.vec3f, 3));
77+
78+
// existing overload
79+
positionsMutable.write([d.vec3f(0, 1, 2), d.vec3f(3, 4, 5), d.vec3f(6, 7, 8)]);
80+
// new overloads ⚡
81+
positionsMutable.write([[0, 1, 2], [3, 4, 5], [6, 7, 8]]); // tuples
82+
positionsMutable.write(new Float32Array([0, 1, 2, 0, 3, 4, 5, 0, 6, 7, 8, 0])); // typed arrays (mind the padding)
83+
// and more...
84+
```
85+
Each one is more efficient than the previous, so you can choose the appropriate API for your efficiency needs.
86+
[More about these new APIs here](https://docs.swmansion.com/TypeGPU/fundamentals/buffers/#writing-to-a-buffer).
87+
88+
### A better partial write
89+
90+
When writing to a buffer, we require the passed in value to exactly match the schema. This specifically means that updating a single field of a single array item was very costly. The `buffer.writePartial` API remedied that by accepting partial records
91+
for structs, and a list of indices and values to update in arrays. This works fine, but doesn't compose well with more complex data structures:
92+
93+
```ts
94+
const Node = d.struct({
95+
color: d.vec3f,
96+
// Indices of neighboring nodes
97+
neighbors: d.arrayOf(d.u32, 4),
98+
});
99+
100+
const nodes = root.createUniform(d.arrayOf(Node, 100));
101+
102+
// Updating the 50th node
103+
nodes.writePartial([
104+
{
105+
idx: 50,
106+
value: {
107+
color: d.vec3f(1, 0, 1),
108+
// We cannot pass [48, 49, 51, 52], as we could with nodes.write()
109+
neighbors: [{ idx: 0, value: 48 }, { idx: 1, value: 49 }, { idx: 2, value: 51 }, { idx: 3, value: 52 }],
110+
},
111+
}
112+
]);
113+
```
114+
115+
If we loosened the type to accept either partial arrays or full arrays, then we would reach an ambiguity in the following case:
116+
117+
```ts
118+
const Foo = d.struct({
119+
idx: d.u32,
120+
value: d.f32,
121+
});
122+
123+
const foos = root.createUniform(d.arrayOf(Foo, 2));
124+
125+
foos.writePartial([{ idx: 1, value: /* ... */ }, { idx: 0, value: /* ... */ }]);
126+
```
127+
128+
We could traverse the value deeper to disambiguate, but for the sake of efficiency and being able to reuse optimizations added to `buffer.write` by [Konrad](https://github.com/reczkok), we chose to add a new API:
129+
130+
```diff lang=ts
131+
- foos.writePartial([{ idx: 1, value: /* ... */ }, { idx: 0, value: /* ... */ }]);
132+
+ foos.patch({ 1: /* ... */, 0: /* ... */ });
133+
```
134+
135+
[You can read more about .patch in the Buffers guide](/TypeGPU/fundamentals/buffers/#patching-buffers).
136+
137+
### Writing struct-of-arrays (SoA) data
138+
139+
When the buffer schema is an `array<struct<...>>`, you can write the data in a struct-of-arrays form with `writeSoA` from `typegpu/common`. This is useful when your CPU-side data is already stored per-field, such as simulation attributes kept in separate typed arrays.
140+
141+
```ts
142+
const Particle = d.struct({
143+
pos: d.vec3f,
144+
vel: d.f32,
145+
});
146+
147+
const particleBuffer = root.createBuffer(d.arrayOf(Particle, 2));
148+
149+
common.writeSoA(particleBuffer, {
150+
pos: new Float32Array([
151+
1, 2, 3,
152+
4, 5, 6,
153+
]),
154+
vel: new Float32Array([10, 20]),
155+
});
156+
```
157+
158+
[More about this API can be found in the Buffers guide.](/TypeGPU/fundamentals/buffers/#writing-struct-of-arrays-soa-data)
159+
160+
## Shader code ergonomics
161+
162+
There's been a lot of improvements to our shader generation, mainly in regards to compile-time execution and pruning of unreachable branches.
163+
I will highlight some of them in the following sections.
164+
165+
### std.range
166+
167+
The new `std.range` function works similarly to `range()` in Python, and returns an array that can be iterated over.
168+
When combined with `tgpu.unroll`, it's now very easy to produce a set amount of code blocks.
169+
170+
```ts
171+
let result = d.u32();
172+
for (const i of tgpu.unroll(std.range(3))) {
173+
// this block will be inlined 3 times
174+
result += i * 10;
175+
}
176+
```
177+
178+
Generates:
179+
```wgsl
180+
var result = 0u;
181+
// unrolled iteration #0
182+
{
183+
result += 0u;
184+
}
185+
// unrolled iteration #1
186+
{
187+
result += 10u;
188+
}
189+
// unrolled iteration #2
190+
{
191+
result += 20u;
192+
}
193+
````
194+
195+
Because `i` is known at compile-time, the `i * 10` is evaluated and injected into the generated code in each block.
196+
For more, refer to [tgpu.unroll documentation.](/TypeGPU/fundamentals/utils/#tgpuunroll).
197+
198+
### Boolean logic
199+
200+
Logical expressions are now short-circuited if we can determine the result early.
201+
```ts
202+
const clampingEnabled = tgpu.accessor(d.bool);
203+
204+
function interpolate(a: number, b: number, t: number) {
205+
'use gpu';
206+
let value = a + (b - a) * t;
207+
if (clampingEnabled.$ && value > 1) {
208+
// Constantly increasing, without ever going past 2
209+
value = 1 + (value - 1) / value;
210+
}
211+
return value;
212+
}
213+
```
214+
215+
Generated WGSL depending on the value of `clampingEnabled`:
216+
217+
```wgsl
218+
// clampingEnabled.$ === false
219+
fn interpolate(a: f32, b: f32, t: f32) -> f32 {
220+
var value = a + (b - a) * t;
221+
return value;
222+
}
223+
224+
// clampingEnabled.$ === true
225+
fn interpolate(a: f32, b: f32, t: f32) -> f32 {
226+
var value = a + (b - a) * t;
227+
if (value > 1) {
228+
value = 1 + (value - 1) / value;
229+
}
230+
return value;
231+
}
232+
```
233+
234+
### Convenience overload for `tgpu.const` API
235+
236+
If you're defining a WGSL constant using an array schema, you no longer have to duplicate the array length both in the value and in the schema.
237+
The `tgpu.const` function now accepts dynamically-sized schemas.
238+
239+
```diff lang=ts
240+
const ColorStops = d.arrayOf(d.vec3f);
241+
242+
const colorStops = tgpu.const(
243+
- ColorStops(3),
244+
+ ColorStops,
245+
[d.vec3f(1, 0, 0), d.vec3f(0, 1, 0), d.vec3f(0, 0, 1)],
246+
);
247+
```
248+
249+
## Ecosystem updates
250+
251+
There has been a lot of work outside of the `typegpu` package, both internally and from the community.
252+
253+
### Lint plugin
254+
255+
Aleksander Katan ([@aleksanderkatan](https://github.com/aleksanderkatan)) has been working behind the scenes on an ESLint/Oxlint plugin, capable of catching user errors that types cannot.
256+
257+
```ts
258+
import tgpu, { d } from 'typegpu';
259+
260+
function increment(n: number) {
261+
'use gpu';
262+
return n++;
263+
// ^^^
264+
// Cannot assign to 'n' since WGSL parameters are immutable.
265+
// If you're using d.ref, please either use '.$' or disable this rule
266+
}
267+
268+
function createBoid() {
269+
'use gpu';
270+
const boid = { pos: d.vec2f(), size: 1 };
271+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
272+
// { pos: d.vec2f(), size: 1 } must be wrapped in a schema call
273+
return boid;
274+
}
275+
276+
function clampTo0(n: number) {
277+
'use gpu';
278+
let result;
279+
// ^^^^^^
280+
// 'result' must have an initial value
281+
if (n < 0) {
282+
result = 0;
283+
} else {
284+
result = n;
285+
}
286+
return result;
287+
}
288+
```
289+
290+
[For setup instructions and available rules, refer to the documentation](/TypeGPU/tooling/eslint-plugin-typegpu/)
291+
292+
### New @typegpu/color helpers
293+
294+
There are three new helper functions importable from `@typegpu/color` which can be called at compile-time to create
295+
color vectors from hexadecimal strings: `hexToRgb`, `hexToRgba` and `hexToOklab`.
296+
297+
```ts
298+
import { hexToRgb } from '@typegpu/color';
299+
300+
function getGradientColor(t: number) {
301+
'use gpu';
302+
const from = hexToRgb('#FF00FF');
303+
const to = hexToRgb('#00FF00');
304+
return std.mix(from, to, t);
305+
}
306+
```
307+
308+
Generated WGSL:
309+
```wgsl
310+
fn getGradientColor(t: f32) -> vec3f {
311+
var from = vec3f(1, 0, 1);
312+
var to = vec3f(0, 1, 0);
313+
return mix(from, to, t);
314+
}
315+
````
316+
317+
### Bundler plugin rewrite
318+
319+
The `unplugin-typegpu` package is what enables TypeScript shaders, and to support its continued development, we rewrote it from
320+
the ground up. It should now support more bundlers than ever before, out of the box, including `esbuild`.
321+
322+
### Motion GPU
323+
324+
A minimalist WebGPU framework called [Motion GPU](https://motion-gpu.dev/) introduced a way to integrate with TypeGPU, and wrote about it
325+
in their documentation [(Integrations / TypeGPU)](https://motion-gpu.dev/docs/integrations-typegpu). It's awesome to see the continued adoption
326+
of TypeGPU in other ecosystems and communities 🎉
327+
328+
## What's next?
329+
330+
There are many more things introduced in TypeGPU 0.11 that I haven't mentioned. If you're curious, you can
331+
read [the full 0.11.0 changelog](https://github.com/software-mansion/TypeGPU/compare/v0.10.2...v0.11.0).

0 commit comments

Comments
 (0)