Repository navigation
Conversation
Each module declares a `__tgpu_meta` helper once, and every 'use gpu' function is registered with `__tgpu_meta(fn, json, externals, name?)`: - the AST is a JSON string (params as plain strings, bare numeric literals) - the function isn't wrapped in parentheses, so V8 compiles it lazily - already transformed code is recognized in both the v2 and v3 shapes
This was referenced Oct 21, 2026
|
pkg.pr.new packages benchmark commit |
Resolution Time Benchmark---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Random Branching (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.91, 1.90, 4.24, 7.14, 7.55, 12.01, 24.06, 24.21]
line [0.86, 1.81, 4.13, 6.52, 8.05, 12.91, 25.61, 24.96]
line [0.94, 1.87, 4.11, 6.49, 6.86, 11.84, 24.51, 25.87]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Linear Recursion (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.30, 0.50, 0.75, 0.90, 1.12, 1.19, 1.40, 1.65]
line [0.34, 0.52, 0.66, 0.75, 1.03, 1.11, 1.31, 1.51]
line [0.34, 0.53, 0.70, 0.86, 1.08, 1.16, 1.38, 1.52]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Full Tree (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.91, 2.08, 3.95, 7.00, 12.75, 26.97, 56.83, 114.95]
line [0.95, 2.25, 3.92, 6.85, 12.35, 25.68, 55.96, 112.79]
line [0.88, 2.11, 4.28, 6.93, 12.01, 26.11, 54.07, 110.49]
|
Bundle size comparison (
|
| 🟢 Decreased (max -23.94%) | ➖ Unchanged | 🔴 Increased | ❔ Unknown |
|---|---|---|---|
| 1 | 351 | 0 | 0 |
import * as ... in PR vs import * as ... in target (did bundle size increase?):
| Test | tsdown |
|---|---|
| STATIC_useGpuFunction.ts | 197 B ( |
If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every
'use gpu'function carries metadata (AST, externals, name) that the WGSL generator needs. In v2 the plugin registered it with an IIFE per function, and stored the AST as an object literal:v3 declares a helper once per module, and keeps the AST in a JSON string:
Changes
nameis omitted when the function has no name.$.f = (…)). Minifiers keep those parentheses, because V8 takes them as a hint to compile the function eagerly at load. Most'use gpu'functions never run on the CPU, so that was wasted work.ext.config.zero), and evaluating them all at once could throw where the original code wouldn't.explaining-the-magic.mdx) are updated.Needs a typegpu version that reads v3 (#3245), so the two have to be released together.
Measurements
Four docs examples with the most
'use gpu'functions, as standalone Vite 8 apps, each built into one minified chunk (the lab is in #3248). Compared against this PR's parent (#3245).Bundle size (bytes, minified / gzip / brotli):
The compressed gain is small. Metadata is 6–16% of these gzipped bundles, but gzip already removes most of the repetitive syntax. What's left is information: identifiers make up about 40% of the metadata's gzip cost, and tree structure most of the rest. Builds with
unstable_obfuscate+unstable_minifysave 213–553 B gzip.Load time: importing each whole production bundle in a fresh Node 24 process. Without WebGPU the apps stop at
tgpu.init(), which runs after all module-level code, so every function's metadata has been registered by then. Median of 31 interleaved runs. Two identical builds measured the same way differ by up to 2%.Metadata alone, including first use: each app's metadata and JS implementations as a standalone script, in v2 and in v3. A fresh Node process compiles and runs it, then reads every function's metadata the way
getFunctionMetadatadoes (v3 parses the JSON here). Median of 21 runs.Removing the parentheses accounts for 0.2–1.2 ms of that (v2 without them: 5.83, 1.73, 4.00, 3.62 ms).
The generated WGSL is unchanged. All docs example tests pass. In Chromium, every shader module of the four apps is byte-identical to
main's (91 modules in monocular-light-injection).Alternatives
Each candidate was produced by re-encoding the metadata in the built bundles, then measuring the resulting bundle. Gzip change vs v2 for monocular-light-injection / jelly-slider, and the share of the metadata's gzip cost (20.4 / 13.0 kB) it removes:
[5, 0.5]nodes