Skip to content

feat: Obfuscate variables in plugin - #2755

Draft
aleksanderkatan wants to merge 29 commits into
mainfrom
feat/minify-variables-in-plugin
Draft

feat: Obfuscate variables in plugin#2755
aleksanderkatan wants to merge 29 commits into
mainfrom
feat/minify-variables-in-plugin

Conversation

@aleksanderkatan

@aleksanderkatan aleksanderkatan commented Jul 23, 2026

Copy link
Copy Markdown
Member
image

We minify variables, externals and parameters. Struct props are left as-is.

I tested it by:

  • going through all examples with minification enabled (apps/typegpu-docs/astro.config.mjs:56),
  • skimming the diffs in updated example snapshots with minification enabled (apps/typegpu-docs/vitest.config.mts:12),
  • seeing all failing tests in typegpu/tests with minification enabled (packages/typegpu/vitest.config.mts:11).

Further work: #2783, #2786.

Also, helpers like fullScreenTriangle will remain as is, they are implemented in raw wgsl.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

pkg.pr.new

packages
Ready to be installed by your favorite package manager ⬇️

https://pkg.pr.new/software-mansion/TypeGPU/eslint-plugin-typegpu@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/tgpu-gen@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/tinyest-for-wgsl@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/typegpu@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/cli@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/color@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/gl@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/noise@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/radiance-cascades@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/react@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/sdf@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/three@a590a52fceb9fe53ad62d58d97813d982886b814
https://pkg.pr.new/software-mansion/TypeGPU/unplugin-typegpu@a590a52fceb9fe53ad62d58d97813d982886b814

benchmark
view benchmark

commit
view commit

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Bundle size comparison (import * as ... in PR vs import * as ... in target):

🟢 Decreased ➖ Unchanged 🔴 Increased (max 0.01%) ❔ Unknown
0 301 21 0

import { ... } in PR vs import * as ... in PR (is the library tree-Shakeable?):

Test tsdown
tgpu_init.ts 260.06 kB ($${\color{green}-3.2\%}$$)
tgpu_initFromDevice.ts 259.53 kB ($${\color{green}-3.4\%}$$)
tgpu_resolve.ts 165.43 kB ($${\color{green}-38.4\%}$$)
tgpu_resolveWithContext.ts 165.37 kB ($${\color{green}-38.4\%}$$)
tgpu_bindGroupLayout.ts 69.27 kB ($${\color{green}-74.2\%}$$)
tgpu_mutableAccessor.ts 66.27 kB ($${\color{green}-75.3\%}$$)
tgpu_accessor.ts 66.26 kB ($${\color{green}-75.3\%}$$)
tgpu_privateVar.ts 65.61 kB ($${\color{green}-75.6\%}$$)
tgpu_workgroupVar.ts 65.60 kB ($${\color{green}-75.6\%}$$)
tgpu_const.ts 64.85 kB ($${\color{green}-75.9\%}$$)
tgpu_fn.ts 38.45 kB ($${\color{green}-85.7\%}$$)
tgpu_fragmentFn.ts 38.45 kB ($${\color{green}-85.7\%}$$)
tgpu_vertexFn.ts 38.27 kB ($${\color{green}-85.8\%}$$)
tgpu_computeFn.ts 37.97 kB ($${\color{green}-85.9\%}$$)
tgpu_vertexLayout.ts 27.08 kB ($${\color{green}-89.9\%}$$)
tgpu_comptime.ts 14.77 kB ($${\color{green}-94.5\%}$$)
tgpu_unroll.ts 1.66 kB ($${\color{green}-99.4\%}$$)
tgpu_slot.ts 1.54 kB ($${\color{green}-99.4\%}$$)
tgpu_lazy.ts 1.19 kB ($${\color{green}-99.6\%}$$)

If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

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.84, 1.66, 3.72, 5.01, 6.05, 10.37, 18.50, 20.48]
  line [0.85, 1.60, 3.59, 5.63, 6.21, 10.12, 18.47, 22.17]
  line [0.86, 1.70, 3.92, 5.16, 6.41, 9.95, 20.66, 22.33]
Loading
---
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.32, 0.48, 0.66, 0.78, 1.05, 1.05, 1.28, 1.43]
  line [0.31, 0.50, 0.65, 0.74, 1.07, 1.08, 1.25, 1.36]
  line [0.29, 0.92, 0.67, 0.79, 1.03, 1.15, 1.35, 1.48]
Loading
---
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.90, 1.88, 3.55, 5.57, 10.33, 22.59, 46.95, 95.18]
  line [0.92, 1.90, 3.06, 5.73, 10.34, 22.43, 46.59, 95.60]
  line [0.85, 1.93, 3.85, 5.69, 10.87, 23.51, 49.53, 100.90]
Loading

declaredNames: string[];
};

export type Externals = Set<string>;

@aleksanderkatan aleksanderkatan Aug 3, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less work swapping it for a map here than in unplugin, and it needs to become a map eventually

@aleksanderkatan aleksanderkatan changed the title feat: Minify variables in plugin feat: Obfuscate variables in plugin Aug 4, 2026
@aleksanderkatan

Copy link
Copy Markdown
Member Author

@pullfrog review

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The externalNames iteration in the obfuscator swaps the map's key and value. This works today only because tinyest-for-wgsl stores identical strings for both; it will silently produce incorrect WGSL if that invariant ever changes.

Reviewed changes — PR #2755 adds an experimental plugin-time obfuscation pass that renames parameters, local variables, and external bindings in the transpiled tinyest AST, plus the EXPERIMENTAL_obfuscate option across the Babel/Rollup/Bun plugin entry points, a new docs page, and supporting test updates.

  • Added packages/unplugin-typegpu/src/core/obfuscate.ts — AST-to-AST obfuscation of params, body, and externalNames.
  • Changed Externals from Set<string> to Map<string, string> in packages/tinyest-for-wgsl/src/types.ts and updated all consumers/test snapshots.
  • Wired EXPERIMENTAL_obfuscate into unplugin-typegpu plugin options, with a guard that rejects enabling it alongside autoNamingEnabled.
  • Added docs entry (apps/typegpu-docs/.../minifying-shaders.mdx) and sidebar link.
  • Updated/added tests in packages/tinyest-for-wgsl/tests/parsers.test.ts, packages/unplugin-typegpu/test/obfuscation.test.ts, and several typegpu snapshot tests.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

const body = obf(ctx, fn.body);

const externalNames = new Map();
fn.externalNames.forEach((key, value) => externalNames.set(ctx.obfuscator.obfuscate(key), value));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Map.prototype.forEach passes (value, key), so the parameter names here are backwards: key receives the original external chain and value receives the AST identifier. Today tinyest-for-wgsl stores the same string for both (externalNames.set(externalChain, externalChain)), so the result is correct by accident. If the map is ever used to store distinct aliases (which the new Map<string, string> type now allows), the obfuscated external key will no longer match the identifiers in the AST body, and the resolved WGSL will reference the wrong value or fail to resolve.

Technical details
# externalNames key/value swap

## Affected sites
- packages/unplugin-typegpu/src/core/obfuscate.ts:78-79 — iterates `externalNames` with swapped key/value parameters

## Required outcome
- The obfuscated map must use `obfuscate(astIdentifier)` as the key and the original JS chain as the value.

## Suggested approach
Replace the `forEach` with a `for...of` to avoid the argument-order trap:

```ts
for (const [key, value] of fn.externalNames) {
  externalNames.set(ctx.obfuscator.obfuscate(key), value);
}

</details>

```suggestion
  const externalNames = new Map();
  for (const [key, value] of fn.externalNames) {
    externalNames.set(ctx.obfuscator.obfuscate(key), value);
  }

  return { params, body, externalNames };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant