Skip to content

Commit c593bfb

Browse files
committed
Merge branch 'main' into release
2 parents 0411ea1 + 5a4c5e8 commit c593bfb

497 files changed

Lines changed: 22464 additions & 8515 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/pkg-pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
run: pnpm nightly-build
3838

3939
- name: Publish (pkg.pr.new)
40-
run: npx pkg-pr-new publish './packages/typegpu/dist' './packages/typegpu-noise/dist' './packages/unplugin-typegpu/dist' --json output.json --comment=off --pnpm
40+
run: pnpm exec pkg-pr-new publish './packages/typegpu' './packages/typegpu-noise' './packages/unplugin-typegpu' --json output.json --comment=off --pnpm --no-compact
4141
- name: Post or update comment
4242
uses: actions/github-script@v6
4343
with:
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Publish release to npm
2+
on:
3+
# For manual releases
4+
workflow_dispatch:
5+
inputs:
6+
dry-run:
7+
description: Whether to perform a dry run of the publish.
8+
type: boolean
9+
default: true
10+
11+
jobs:
12+
npm-build:
13+
if: github.repository == 'software-mansion/TypeGPU'
14+
runs-on: ubuntu-latest
15+
16+
permissions:
17+
contents: write
18+
id-token: write # for OIDC
19+
20+
concurrency:
21+
group: publish-${{ github.ref }}
22+
cancel-in-progress: false
23+
24+
steps:
25+
- name: Check out
26+
uses: actions/checkout@v4
27+
28+
- name: Install pnpm
29+
uses: pnpm/action-setup@v4
30+
with:
31+
run_install: false
32+
33+
- name: Use Node.js 24.x
34+
uses: actions/setup-node@v4
35+
with:
36+
node-version: 24.x
37+
cache: 'pnpm'
38+
39+
- name: Install dependencies
40+
run: pnpm install --frozen-lockfile
41+
42+
- name: Publish manual release
43+
if: ${{ github.event_name == 'workflow_dispatch' }}
44+
env:
45+
DISABLE_DRY_RUN: ${{ inputs['dry-run'] == false }}
46+
run: pnpm exec bun scripts/publish.ts
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
name: Resolution time benchmark
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
resolution-time:
8+
if: github.event.pull_request.head.repo.full_name == github.repository
9+
permissions:
10+
contents: read
11+
pull-requests: write
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Install pnpm
15+
uses: pnpm/action-setup@v4
16+
with:
17+
version: 10.27.0
18+
run_install: false
19+
20+
- name: Checkout PR branch
21+
uses: actions/checkout@v4
22+
with:
23+
path: pr-branch
24+
25+
- name: Checkout target branch
26+
uses: actions/checkout@v4
27+
with:
28+
path: target-branch
29+
ref: ${{ github.base_ref }}
30+
31+
- name: Checkout latest release
32+
uses: actions/checkout@v4
33+
with:
34+
path: release-branch
35+
ref: release
36+
37+
- name: Copy resolution-time app to release checkout
38+
run: |
39+
if [ ! -d release-branch/apps/resolution-time ]; then
40+
cp -r target-branch/apps/resolution-time release-branch/apps/resolution-time
41+
echo "Copied resolution-time app from target branch to release checkout"
42+
else
43+
echo "resolution-time app already exists in release checkout"
44+
fi
45+
46+
- name: Set up Node.js
47+
uses: actions/setup-node@v4
48+
with:
49+
node-version: 24.x
50+
cache: 'pnpm'
51+
cache-dependency-path: |
52+
pr-branch/pnpm-lock.yaml
53+
target-branch/pnpm-lock.yaml
54+
release-branch/pnpm-lock.yaml
55+
56+
- name: Install dependencies (PR branch)
57+
working-directory: pr-branch
58+
run: pnpm install --frozen-lockfile
59+
60+
- name: Install dependencies (target branch)
61+
working-directory: target-branch
62+
run: pnpm install --frozen-lockfile
63+
64+
- name: Install dependencies (release branch)
65+
working-directory: release-branch
66+
run: pnpm install --no-frozen-lockfile
67+
68+
- name: Run benchmark (PR branch)
69+
working-directory: pr-branch
70+
run: pnpm --filter resolution-time resolution-time
71+
72+
- name: Run benchmark (target branch)
73+
working-directory: target-branch
74+
run: pnpm --filter resolution-time resolution-time
75+
76+
- name: Run benchmark (release branch)
77+
working-directory: release-branch
78+
run: pnpm --filter resolution-time resolution-time
79+
80+
- name: Generate chart (random)
81+
run: |
82+
node pr-branch/apps/resolution-time/generateChart.ts \
83+
--input "PR:pr-branch/apps/resolution-time/results-random.json" \
84+
--input "main:target-branch/apps/resolution-time/results-random.json" \
85+
--input "release:release-branch/apps/resolution-time/results-random.json" \
86+
--title "Random Branching" \
87+
--xAxisTitle "max depth" \
88+
--yAxisTitle "time (ms)" \
89+
--output chart-random.md
90+
91+
- name: Generate chart (linear)
92+
run: |
93+
node pr-branch/apps/resolution-time/generateChart.ts \
94+
--input "PR:pr-branch/apps/resolution-time/results-linear-recursion.json" \
95+
--input "main:target-branch/apps/resolution-time/results-linear-recursion.json" \
96+
--input "release:release-branch/apps/resolution-time/results-linear-recursion.json" \
97+
--title "Linear Recursion" \
98+
--xAxisTitle "max depth" \
99+
--yAxisTitle "time (ms)" \
100+
--output chart-linear.md
101+
102+
- name: Generate chart (max depth)
103+
run: |
104+
node pr-branch/apps/resolution-time/generateChart.ts \
105+
--input "PR:pr-branch/apps/resolution-time/results-max-depth.json" \
106+
--input "main:target-branch/apps/resolution-time/results-max-depth.json" \
107+
--input "release:release-branch/apps/resolution-time/results-max-depth.json" \
108+
--title "Full Tree" \
109+
--xAxisTitle "max depth" \
110+
--yAxisTitle "time (ms)" \
111+
--output chart-max-depth.md
112+
113+
- name: Prepare comment
114+
run: |
115+
{
116+
echo "## Resolution Time Benchmark"
117+
echo ""
118+
cat chart-random.md
119+
echo ""
120+
cat chart-linear.md
121+
echo ""
122+
cat chart-max-depth.md
123+
} > comparison.md
124+
125+
- name: Comment PR with results
126+
uses: actions/github-script@v7
127+
with:
128+
script: |
129+
const fs = require('fs');
130+
const comparison = fs.readFileSync('comparison.md', 'utf8');
131+
132+
const botCommentIdentifier = '<!-- resolution-time-bot-comment -->';
133+
134+
async function findBotComment(issueNumber) {
135+
if (!issueNumber) return null;
136+
const comments = await github.rest.issues.listComments({
137+
owner: context.repo.owner,
138+
repo: context.repo.repo,
139+
issue_number: issueNumber,
140+
});
141+
return comments.data.find((comment) =>
142+
comment.body.includes(botCommentIdentifier)
143+
);
144+
}
145+
146+
async function createOrUpdateComment(issueNumber) {
147+
if (!issueNumber) {
148+
console.log('No issue number provided. Cannot post or update comment.');
149+
return;
150+
}
151+
152+
const existingComment = await findBotComment(issueNumber);
153+
if (existingComment) {
154+
await github.rest.issues.updateComment({
155+
...context.repo,
156+
comment_id: existingComment.id,
157+
body: botCommentIdentifier + '\n' + comparison,
158+
});
159+
} else {
160+
await github.rest.issues.createComment({
161+
...context.repo,
162+
issue_number: issueNumber,
163+
body: botCommentIdentifier + '\n' + comparison,
164+
});
165+
}
166+
}
167+
168+
const issueNumber = context.issue.number;
169+
if (!issueNumber) {
170+
console.log('No issue number found in context. Skipping comment.');
171+
} else {
172+
await createOrUpdateComment(issueNumber);
173+
}
174+
await core.summary
175+
.addRaw(comparison)
176+
.write();

.github/workflows/treeshake-test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ on:
1111

1212
jobs:
1313
treeshake-test:
14+
if: github.event.pull_request.head.repo.full_name == github.repository
1415
permissions:
1516
contents: read
1617
issues: write

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ yarn-error.log*
3131
.DS_Store
3232
.idea
3333
.husky
34+
35+
# agents
36+
.claude

CONTRIBUTING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ pnpm publish --dry-run # (if alpha, --tag alpha)
4343
```
4444

4545
5. If everything looks okay, then `pnpm publish` (if alpha, `--tag alpha`)
46+
47+
> **Tip:** If you already know all prepublish checks pass (tests, types, publish tag validation), you can skip them to speed up
48+
> publishing:
49+
>
50+
> ```bash
51+
> SKIP_TESTS=true pnpm publish # (if alpha, --tag alpha)
52+
> ```
53+
4654
6. Rebase _release_ branch on _main_
4755
7. Generate and edit release notes on GitHub
4856
8. Run `npx automd@latest`

apps/bun-example/preload.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import { plugin } from 'bun';
22
import typegpu from 'unplugin-typegpu/bun';
33

4-
void plugin(typegpu({ include: /\.(ts)$/ }));
4+
void plugin(typegpu());

apps/resolution-time/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Procedural TypeGPU function generator for benchmarking resolution time
2+
3+
## Adding a new instruction
4+
5+
Each instruction is a `tgpu.comptime` that returns a `tgpu.fn(() => void)`. There are two kinds: **leaf** (no function calls) and **recursive** (branches into other instructions).
6+
7+
### Leaf instruction
8+
9+
```ts
10+
const myLeafFn = tgpu.comptime(() => {
11+
return tgpu.fn(() => {
12+
'use gpu';
13+
// ...
14+
popDepth(); // REQUIRED — always call at the end
15+
}).$name('myLeafFn');
16+
});
17+
```
18+
19+
### Recursive instruction
20+
21+
Use `tgpu.unroll` over `std.range(n)` and call `instructions[choice()]()()` to branch into other instructions. The `choice()` function handles depth tracking and picks a leaf when at max depth.
22+
23+
```ts
24+
const myRecursiveFn = tgpu.comptime(() => {
25+
return tgpu.fn(() => {
26+
'use gpu';
27+
// ...
28+
for (const _i of tgpu.unroll(std.range(n))) {
29+
instructions[choice()]()();
30+
}
31+
popDepth(); // REQUIRED — always call at the end, after the unroll
32+
}).$name('myRecursiveFn');
33+
});
34+
```
35+
36+
## Generating Mermaid charts
37+
38+
`generateChart.ts` reads benchmark result JSON files and outputs a Mermaid xychart comparing up to 3 datasets.
39+
40+
### Usage
41+
42+
```sh
43+
node generateChart.ts \
44+
--input "PR:pr-branch/results-max-depth.json" \
45+
--input "main:main-branch/results-max-depth.json" \
46+
--title "Resolution Time vs Max Depth" \
47+
--xAxisTitle "max depth" \
48+
--yAxisTitle "time (ms)" \
49+
--output chart.md
50+
```
51+
52+
### Arguments
53+
54+
| Argument | Required | Description |
55+
|---|---|---|
56+
| `--input <label>:<path>` | yes (1-3) | `label` appears in the legend, `path` points to a benchmark results JSON file generated by `procedural.ts` |
57+
| `--title <text>` | yes | chart title |
58+
| `--xAxisTitle <text>` | no | x-axis title |
59+
| `--yAxisTitle <text>` | no | y-axis title |
60+
| `--output <path>` | no | write markdown to a file instead of stdout |
61+
62+
Each `--input` dataset is plotted as a separate line on the same chart. Colors are assigned in order: red, blue, green.

apps/resolution-time/bunfig.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
preload = ["./preload.ts"]

0 commit comments

Comments
 (0)