Repository navigation
Conversation
|
pkg.pr.new packages benchmark commit |
Bundle size comparison (
|
| 🟢 Decreased | ➖ Unchanged | 🔴 Increased | ❔ Unknown |
|---|---|---|---|
| 0 | 355 | 0 | 0 |
No notable changes.
If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.
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 [1.10, 2.31, 4.72, 7.36, 8.25, 13.13, 25.75, 25.85]
line [1.04, 2.09, 4.47, 7.36, 8.22, 13.16, 27.02, 27.90]
line [0.96, 1.99, 4.57, 6.88, 8.32, 13.29, 26.47, 27.50]
---
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.35, 0.61, 0.77, 0.92, 1.29, 1.28, 1.50, 1.75]
line [0.32, 0.53, 0.73, 0.86, 1.22, 1.33, 1.52, 1.67]
line [0.33, 0.57, 0.73, 0.90, 1.18, 1.23, 1.46, 1.67]
---
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.83, 2.22, 3.88, 7.59, 13.52, 28.41, 58.55, 121.08]
line [0.87, 2.21, 3.99, 8.15, 15.02, 27.56, 58.74, 120.44]
line [1.07, 2.45, 4.29, 7.80, 13.28, 27.54, 59.57, 119.95]
|
4af9244 to
b452155
Compare
|
Please take a look at my (almost finished) branch, if you would like to incorporate any of it, or steal techniques https://github.com/deluksic/TypeGPU/tree/de/geometry-spheres (it is more than spheres) |
b452155 to
434811e
Compare
1e09d9b to
6246334
Compare
6246334 to
58c4fcb
Compare
58c4fcb to
043c0ab
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Baked-index consistency and primitive boundaries during concatenation need correction before approval.
2 open issues
1 file not reviewed
pnpm-lock.yaml: Generated file
What changed in this PR
Adds a composable meshes API to @typegpu/geometry, supporting procedural 3D geometry, shader evaluation, and GPU buffer baking.
Changes:
- Introduces primitives, parametric surfaces, and geometry transformations and composition.
- Adds full and index-only baking, asynchronous preparation, and compute-driven vertex updates.
- Adds tests and an animated mesh gallery with shadows.
| File | Description |
|---|---|
pnpm-lock.yaml |
Records geometry testing dependencies. |
packages/typegpu-geometry/vitest.config.mts |
Configures shader-aware unit tests. |
packages/typegpu-geometry/tsconfig.test.json |
Enables test type checking. |
packages/typegpu-geometry/tests/updates.test.ts |
Tests baking updates, bindings, and dispatch. |
packages/typegpu-geometry/tests/mesh.test.ts |
Tests primitives and geometry composition. |
packages/typegpu-geometry/tests/fixtures.ts |
Adds shared geometry and shader fixtures. |
packages/typegpu-geometry/tests/bake.test.ts |
Tests baking, buffer ownership, and pipeline injection. |
packages/typegpu-geometry/src/mesh/primitives.ts |
Implements five primitives and surface evaluators. |
packages/typegpu-geometry/src/mesh/parametric.ts |
Implements grid sampling and estimated normals. |
packages/typegpu-geometry/src/mesh/math.ts |
Adds coordinate-frame helpers. |
packages/typegpu-geometry/src/mesh/index.ts |
Exports the mesh API. |
packages/typegpu-geometry/src/mesh/geometry.ts |
Defines geometry contracts and vertex layouts. |
packages/typegpu-geometry/src/mesh/fill.ts |
Implements compute-based buffer filling. |
packages/typegpu-geometry/src/mesh/combinators.ts |
Implements transforms, mapping, attachment, and concatenation. |
packages/typegpu-geometry/src/mesh/bake.ts |
Implements baking and baked-mesh operations. |
packages/typegpu-geometry/src/index.ts |
Exposes the meshes namespace. |
packages/typegpu-geometry/package.json |
Adds test scripts and dependencies. |
apps/typegpu-docs/tests/individual-example-tests/mesh-primitives.test.ts |
Tests example shader resolution. |
apps/typegpu-docs/src/examples/rendering/mesh-primitives/spring.ts |
Defines an animated procedural spring. |
apps/typegpu-docs/src/examples/rendering/mesh-primitives/shading.ts |
Implements lighting and shadow sampling. |
apps/typegpu-docs/src/examples/rendering/mesh-primitives/meta.json |
Registers the example metadata. |
apps/typegpu-docs/src/examples/rendering/mesh-primitives/index.ts |
Sets up rendering, animation, and cleanup. |
apps/typegpu-docs/src/examples/rendering/mesh-primitives/index.html |
Provides the example canvas. |
apps/typegpu-docs/src/examples/rendering/mesh-primitives/geometry.ts |
Adds placement and color helpers. |
apps/typegpu-docs/src/examples/rendering/mesh-primitives/gallery.ts |
Arranges the primitive gallery. |
apps/typegpu-docs/src/examples/rendering/mesh-primitives/blob.ts |
Defines an animated parametric blob. |
Review effort: Balanced
There was a problem hiding this comment.
ℹ️ No critical issues — two consistency/robustness points inline.
Reviewed changes
Reviewed the full meshes namespace in @typegpu/geometry and the new mesh-primitives example at 043c0ab.
meshesgeometry model —Geometry/IndexedGeometry(schema +vertexAt/indexAt),Surfacedefault schema,isIndexed, WeakMap-cached vertex layouts.- Primitives & parametric —
plane/box/sphere/cylinder/torus, thesurfaceshelpers, and grid sampling with finite-difference normals. - Combinators —
transform(inverse-transpose normal matrix + winding reversal on reflection),map,attach,unindexed,concat. - Baking —
bake/bakeAsyncandbakeIndices/bakeIndicesAsync, compute-driven fills, buffer ownership anddestroysemantics. - Example & tests — animated shadowed gallery example; CPU geometry/winding tests, bake and update tests, and the example WGSL snapshot.
Verification: packages/typegpu-geometry tests (26 passed), the mesh-primitives example snapshot (1 passed), test:types, oxfmt --check, and oxlint --max-warnings=0 all pass locally.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
ℹ️ No new issues in the latest commits — one earlier thread (the
concatboundary) still stands; the rest of this delta is clean.
Reviewed changes
Reviewed the 7 commits pushed since the prior pullfrog review at 043c0ab (350d0ca6..0b0b53a).
- Build migrated to
tsdown— replacedunbuildwith atsdown.config.tsand updatedpackage.jsonexports/dependencies to match the sibling packages. beveljoin added — newlines/joins/bevel.ts, registered injoins, andmiterJoinLimitSlotis now exported.- Normal matrix hardened —
transformnow uses a sign-corrected cofactor matrix instead of the inverse transpose, so flattening transforms keep valid normals and collapsed normals stay zero. - Fill recording unified —
fill.tsgainedrecordFills, sobake/updateVerticesrecord vertex and index fills into a single compute pass and honour a caller-supplied encoder/pass without submitting. - Buffer offsets added —
bake/bakeIndicesacceptbaseVertex/firstIndexto pack several meshes into shared buffers; the bakedindexAtnow reads the baked index buffer (resolves the earlier stale-indexAtthread). sphereoptions renamed —segments/rings→radialSegments/heightSegments, matchingcylinder; callers and tests updated.- Tests — new
lines.test.ts, offset-baking cases inbake.test.ts, and a flattening-normals case inmesh.test.ts.
Verification at 0b0b53a: @typegpu/geometry tests (31 passed), the mesh-primitives example snapshot (1 passed), test:types, and the tsdown build all pass.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
ℹ️ No new issues in the re-reviewed commits — the earlier
concatboundary thread remains open, so this is not an approval.
Reviewed changes
Re-reviewed the 7 commits pushed after 043c0ab0 (through 0b0b53a1) that make up this synchronize event's delta.
- Build migrated to
tsdown—unbuildandbuild.config.tswere replaced by atsdown.config.tsusingunplugin-typegpu/rolldownandunbundle: true, matching@typegpu/sdfand@typegpu/sort, with the dependentpackage.jsonexports/mainand the lockfile updated. beveljoin added —lines/joins/bevel.tswas added and registered injoins, andmiterJoinLimitSlotis now re-exported.- Normal matrix hardened —
transformnow uses a sign-corrected cofactor matrix, so flattening transforms keep valid normals and reflected normals stay outward. - Fill recording unified —
fill.tsgainedRecordOptionsandrecordFills, sobakeandupdateVerticesrecord vertex and index fills into a single compute pass and honour a caller-supplied encoder or pass without submitting. - Buffer offsets added —
bake/bakeIndicesacceptbaseVertex/firstIndex, and the bakedindexAtreads the baked index buffer. sphereoptions renamed —segments/ringswere renamed toradialSegments/heightSegments, matchingcylinder.- Tests — added
lines.test.ts, plus offset-baking and flattening-normals cases.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
ℹ️ No new issues in the commits reviewed since the last pullfrog review — the earlier
concatboundary thread remains open, so this is not an approval.
Reviewed changes
Re-reviewed the 7 commits pushed after 043c0ab (through 0b0b53a1): the tsdown build migration, the bevel join, the hardened normal matrix, unified fill recording, buffer-offset baking, and the sphere option rename.
- Build migrated to
tsdown—build.config.tswas replaced bytsdown.config.ts(unplugin-typegpu/rolldown,unbundle: true, ESM), with the dependentpackage.jsonpublish exports/mainand dev dependencies updated to match@typegpu/sdf/@typegpu/sort. beveljoin added —lines/joins/bevel.tscuts the outside of a turn with a straight edge, andmiterJoinLimitSlotis now re-exported from the joins barrel.- Normal matrix hardened —
transformnow builds a sign-corrected cofactor matrix instead of the inverse transpose, so transforms that flatten or reflect a shape keep valid outward normals rather than collapsing or flipping them. - Fill recording unified —
fill.tsgainedRecordOptions/recordFills, sobakeandupdateVerticesrecord vertex and index fills into a single compute pass and honour a caller-supplied encoder or pass without submitting. - Buffer offsets added —
bake/bakeIndicesacceptbaseVertex/firstIndexso several meshes can pack into shared buffers, and the bakedindexAtnow reads the baked index buffer. sphereoptions renamed —segments/ringsbecameradialSegments/heightSegments, matchingcylinder; callers and tests were updated.- Tests — added
lines.test.ts(bevel geometry and slot configuration) plus offset-baking, single-pass recording, and flattening-normals cases.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
ℹ️ No new issues in the follow-up commit — the earlier
concatboundary thread remains open, so this is not an approval.
Reviewed changes
Reviewed the single commit pushed after the prior pullfrog review (0b0b53a → 95e1ad5b).
- Example helpers widened —
paint/placein themesh-primitivesexample now taked.InferInput<d.Vec3f>(arrays, tuples, or vectors) and normalise tod.vec3finternally, so callers pass plain arrays andgallery.tsno longer importsd.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
aleksanderkatan
left a comment
There was a problem hiding this comment.
Enormous PR!
I leave mostly nits and questions
| /** Default vertex schema for primitives */ | ||
| export const Surface = d.struct({ position: d.vec3f, normal: d.vec3f, uv: d.vec2f }); | ||
|
|
||
| export type Topology = 'triangle-list' | 'line-list' | 'point-list'; |
There was a problem hiding this comment.
What about 'triangle-strip'? I assume that some combinators would break.
Can we make it work in the future, and throw in combinators that don't support it? Or is it not worth it?
There was a problem hiding this comment.
Yeah i kinda ignored it since it introduces a lot of complexity and tbh I didn't see it a lot in the wild, whether is worth it is a good question I do not have a good answer too
|
|
||
| export type Topology = 'triangle-list' | 'line-list' | 'point-list'; | ||
|
|
||
| export interface Geometry<V extends d.AnyWgslData = typeof Surface> { |
There was a problem hiding this comment.
nit: d.AnyWgslData lets through types that won't work, like pointers or comparison sampler, can we tighten this type?
I'd allow here anything that can be returned by 'use gpu' functions. bool won't work when baked into a buffer, but it will be fine if called in runtime.
There was a problem hiding this comment.
Could you add analogous tests for bakeIndices?
| function windingAgreesWithNormals(g: meshes.IndexedGeometry) { | ||
| for (let t = 0; t < g.indexCount; t += 3) { |
There was a problem hiding this comment.
nit (so that we don't accidentally add a wrong shape to it.each)
| function windingAgreesWithNormals(g: meshes.IndexedGeometry) { | |
| for (let t = 0; t < g.indexCount; t += 3) { | |
| function windingAgreesWithNormals(g: meshes.IndexedGeometry) { | |
| if (g.topology !== 'triangle-list') throw new Error('Invalid topology.'); | |
| for (let t = 0; t < g.indexCount; t += 3) { |
| import { d, tgpu, type TgpuVertexLayout } from 'typegpu'; | ||
|
|
||
| /** Default vertex schema for primitives */ | ||
| export const Surface = d.struct({ position: d.vec3f, normal: d.vec3f, uv: d.vec2f }); |
There was a problem hiding this comment.
This type does not really make sense for non 'triangle-list' topologies, right?
There was a problem hiding this comment.
I mean does it work? Yes. Does it make a lot of sense? Nah not really but you cannot do much with the line and point topologies in webgpu anyways
There was a problem hiding this comment.
Free test
it('throws when attaching a field that is already present', () => {
const Paint = d.struct({ position: d.vec3f });
expect(() =>
meshes.attach(meshes.plane(), Paint, (s) => {
'use gpu';
return Paint({ position: d.vec3f(s.uv, 0) });
}),
).toThrowErrorMatchingInlineSnapshot(
`[Error: attach cannot replace the existing field 'position'; use map instead]`,
);
});| const fan = radialSegments * 3; | ||
|
|
||
| return { | ||
| ...grid, |
There was a problem hiding this comment.
nit: A comment explaining why we override indexing that is technically correct would be nice
| heightSegments = 1, | ||
| caps = true, | ||
| }: CylinderOptions = {}): IndexedGeometry { | ||
| const side = sampleGrid( |
There was a problem hiding this comment.
Can we use surfaces.cylinder here? Same question about surfaces.torus
There was a problem hiding this comment.
yeah, we can - will do
|
|
||
| return { | ||
| initAsync: async () => { | ||
| if (count > 0) await pipeline.initAsync(); |
There was a problem hiding this comment.
nit: We had a soft convention of always including blocks in if, while etc., are we dropping it?
There was a problem hiding this comment.
nope, will add them
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Reviewed the delta since the prior pullfrog review at 95e1ad5b — the single "address review" commit 4330f17.
- Mesh generics tightened —
ConstructibleSchema(Extract<d.AnyWgslData, () => unknown>) moved intogeometry.ts, exported, and applied in place ofd.AnyWgslDataacrossGeometry,IndexedGeometry,isIndexed,layoutOf,map,unindexed,concat, and thebake/bakeIndicesfamily. - Primitives reuse surface helpers —
cylinder's side andtorusnow callsurfaces.cylinder/surfaces.torus; verified algebraically identical to the inline math they replace, including thesurfaces.torus(u, v, 0, 1)unit normal.spherenow documents why it skips the pole triangles. - Brace convention restored — single-statement
if/awaitbodies infill.ts,bake.ts,primitives.ts, andcombinators.tsnow use block braces. - Tests added —
bakeIndicesanalogues (proceduralvertexAt, index-only injection, offset baking, encoder recording), anattachfield-collision test, and a topology guard inwindingAgreesWithNormals.
Verification at 4330f17: @typegpu/geometry tests (36 passed), the mesh-primitives example snapshot (1 passed), and pnpm --filter @typegpu/geometry test:types (both tsconfigs) all pass.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏


Adds
meshesto@typegpu/geometry. Geometry is a vertex schema +vertexAt(and optionallyindexAt), so primitives and transformations compose before anything needs a bufferInteractive cloth example and docs will follow in separate PRs