Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/camp-dev-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@camp-dev/shaders': minor
'@camp-dev/shaders-react': minor
'@camp-dev/shaders-cli': minor
---

The three packages are renamed. `@lovo/matter` is now `@camp-dev/shaders`, `@lovo/matter-react` is now `@camp-dev/shaders-react`, and `@lovo/matter-cli` is now `@camp-dev/shaders-cli`. The repository moved to github.com/campdotdev/shaders. Update your dependency names and every import specifier. Apart from the removals below, the exports themselves are unchanged.

The CLI binary is renamed from `matter-cli` to `shaders-cli`, and its config file from `matter.config.json` to `shaders.config.json`. Rename the file and update any script that calls the old binary. Two defaults that `shaders-cli init` writes also change: `componentsDir` goes from `src/components/matter` to `src/components/shaders`, and `registryUrl` now points at `campdotdev/shaders` instead of `lovo-hq/matter`. A config you already have keeps the values it records, so edit its `registryUrl` by hand or re-run `init` with `--force`.

`MatterError` and `MatterErrorCode` in `@camp-dev/shaders-react` are now `ShadersError` and `ShadersErrorCode`. A `catch` block that tests `instanceof MatterError` has to switch to the new name.

The READMEs drop their migration notes for the `Matter*` aliases that 0.4.0 deprecated, such as `MatterScene` and `MatterScheduler`. The aliases themselves left the source several releases ago.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [["@mattermix/shaders", "@mattermix/shaders-react", "@mattermix/shaders-cli"]],
"fixed": [["@camp-dev/shaders", "@camp-dev/shaders-react", "@camp-dev/shaders-cli"]],
"linked": [],
"access": "public",
"baseBranch": "main",
Expand Down
13 changes: 0 additions & 13 deletions .changeset/mattermix-move.md

This file was deleted.

2 changes: 1 addition & 1 deletion .changeset/stable-hash-backend-parity.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
'@mattermix/shaders': minor
'@camp-dev/shaders': minor
---

Seeded randomness now renders the same pattern on the WebGPU and WebGL2 backends. three's TSL `hash()` writes its PCG constants as float literals, which GLSL rounds to a different hash than WGSL computes, so the same `seed` produced a different Voronoi layout in Safari than in Chrome. The new `stableHash` and `stableHashUint` exports run the same PCG with integer-typed constants and chain hash streams u32 to u32, and `voronoiCells`, `grain`, `metaballs`, and `ditherPattern` now draw from them.
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/resolve-coderabbit-feedback/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ pnpm test --filter <touched package>

Four repo traps apply here:

- If a fix changed source under `packages/shaders` or `packages/shaders-react`, run `pnpm --filter @mattermix/shaders build`. The docs site consumes `dist`, so an unbuilt fix looks like no fix at all.
- If a fix changed source under `packages/shaders` or `packages/shaders-react`, run `pnpm --filter @camp-dev/shaders build`. The docs site consumes `dist`, so an unbuilt fix looks like no fix at all.
- If a fix changed a dependency in any `package.json`, commit the updated `pnpm-lock.yaml` with it, and check that the lockfile still pins `node@runtime` at `version: 22.22.2` with `hasBin: true`. Every pnpm resolution step rewrites that entry to `0.0.0`, and CI then dies at install in every job.
- Never run `pnpm snap` as part of this workflow. Ask first. It needs Docker and Node 22, it takes a long time, and it corrupts a running docs or editor dev server.
- If you ran Playwright or `pnpm snap` for any reason, tell the user to restart the dev server before trusting the browser. The procedure is in `AGENTS.md` under the environment gotchas.
Expand Down Expand Up @@ -296,7 +296,7 @@ Pick `<type>` from the file class the approved fixes touched, and add no AI attr
| A workflow under `.github/` | `ci` |
| Tests, tooling config, or a lockfile on its own | `chore` |

The command above supplies the colon, so these values carry none. Scope is the package name without the `@mattermix/` prefix. When a run spans classes, name the class that carries the substantive fix, so a code fix that drags a lockfile with it stays `fix(<scope>)`. The user already saw the commit line in the Step 6 preview, so change it there rather than asking again here.
The command above supplies the colon, so these values carry none. Scope is the package name without the `@camp-dev/` prefix. When a run spans classes, name the class that carries the substantive fix, so a code fix that drags a lockfile with it stays `fix(<scope>)`. The user already saw the commit line in the Step 6 preview, so change it there rather than asking again here.

## Step 10: Reply and resolve the threads

Expand Down
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Milestone history lives in git tags and `docs/superpowers/plans/`. Don't trust a
## Project shape (30-second version)

- **Three-tier model.** Tier 1 is the polished components such as `<LinearGradient>`, delivered by shadcn-style CLI copy-paste from `registry/`. Tier 2 is the TSL primitives in the engine package, such as `fractalNoise` and `voronoi`. Tier 3 is recipes: TSL snippets in the docs site.
- **Three packages.** `@mattermix/shaders` is the framework-agnostic engine, `@mattermix/shaders-react` is the React binding, and `@mattermix/shaders-cli` handles copy-paste delivery. Two apps sit alongside them: `@shaders/docs` is the docs site, and `@shaders/editor` is the node editor from MAT-94. The editor is a React Flow canvas over the same Tier 2 primitives, with an eject-to-code emitter. A permanent parity gate pixel-compares that emitter's output against the live compiler.
- **Three packages.** `@camp-dev/shaders` is the framework-agnostic engine, `@camp-dev/shaders-react` is the React binding, and `@camp-dev/shaders-cli` handles copy-paste delivery. Two apps sit alongside them: `@shaders/docs` is the docs site, and `@shaders/editor` is the node editor from MAT-94. The editor is a React Flow canvas over the same Tier 2 primitives, with an eject-to-code emitter. A permanent parity gate pixel-compares that emitter's output against the live compiler.
- **The editor app is layered by dependency direction**, not by file type. `src/editor/graph/` is the framework-free core, holding the node registry, graph model, param store, live TSL compiler, and code emitter. `src/editor/preset/` handles save, load, undo, and copy-paste, and is also React-free. `src/editor/state/` is the React Flow glue. `canvas/`, `params/`, and `panels/` are UI. Dependencies point one way, toward `graph/`. Siblings import each other as `./x` and everything else as `@/editor/<folder>/<file>`. `vitest.config.ts` has to declare that `@` alias itself, because Vitest doesn't read tsconfig `paths`.
- **Two rendering modes**, with no auto-detection of `@react-three/fiber`. In Mode 1 every Tier 1 component is bare and requires an explicit `<ShaderScene>` wrap, and you compose by stacking children in one scene. In Mode 2 you call `useShaderMaterial` inside your own r3f `<Canvas>`.

Expand All @@ -37,7 +37,7 @@ Read the spec for architecture, public APIs, the component catalog, and the anim
- **Rejected alternatives only when a reviewer would otherwise propose them.** Dead ends you hit along the way are session debrief. PR #93 spent a paragraph on a rejected triangle wave and another on PNG versus JPEG byte counts, and neither changes an approve or request-changes call.
- **Anything already recorded in the diff gets a clause, not a section.** If the reasoning is in a code comment, in AGENTS.md, or in a changeset this PR adds, write "documented in X" and stop. Restating it makes a second copy that drifts from the first.
- **Run user-facing prose through the `technical-writing` skill**, which also applies `unslop` for the slop-pattern catalog. Look for the skill in the repo's `.claude/skills/` first, then in whatever directory your harness keeps skills in, which is `~/.claude/skills/` for Claude Code. PR bodies, commit messages, changelog entries, release notes, and docs get a pass before the PR opens or the text ships. The skill sets `disable-model-invocation: true`, so an agent that honors that field never loads it on its own. Read its `SKILL.md` and work the review checklist at the end. Its first rule is to cut every word that does no work, so it pulls toward the PR word budget rather than against it. Diátaxis mode selection is the one layer a PR body skips.
- **Commit messages use Conventional Commits**, such as `feat(scope): …`, `fix(scope): …`, `chore: …`, `docs: …`, and `ci: …`. Scope is the package name without the `@mattermix/` prefix.
- **Commit messages use Conventional Commits**, such as `feat(scope): …`, `fix(scope): …`, `chore: …`, `docs: …`, and `ci: …`. Scope is the package name without the `@camp-dev/` prefix.

## Shader development process

Expand Down Expand Up @@ -85,10 +85,10 @@ These rules exist because Shaders doubles as a shader-learning project for its a
## Environment and build gotchas

- **Node 22, exactly.** The docs production build (`next build`, static export) **silently fails on Node 23**. It exits 0 and writes no `out/`, and that missing directory then breaks pagefind and `pnpm snap`. The fix is environmental, so run the pinned Node 22 rather than changing config. `.node-version` at 22.22.2 is the source of truth. `.nvmrc` at 22 is the loose duplicate fnm actually honors.
- **The docs site consumes built `dist`, not source**, for `@mattermix/shaders` and `@mattermix/shaders-react`. `@shaders/registry` is the exception, and reaches the site as raw `.tsx` via `transpilePackages`. After you edit engine or binding source, run `pnpm --filter @mattermix/shaders build` AND restart the docs dev server, or a correct fix looks like a no-op. Before you re-debug a "fix that didn't work," check `dist` mtime against `src`.
- **The docs site consumes built `dist`, not source**, for `@camp-dev/shaders` and `@camp-dev/shaders-react`. `@shaders/registry` is the exception, and reaches the site as raw `.tsx` via `transpilePackages`. After you edit engine or binding source, run `pnpm --filter @camp-dev/shaders build` AND restart the docs dev server, or a correct fix looks like a no-op. Before you re-debug a "fix that didn't work," check `dist` mtime against `src`.
- **CI runs more than package-scoped checks.** Five traps:
1. `pnpm install --frozen-lockfile` runs first in every job. Any `package.json` dep change must ship with the updated `pnpm-lock.yaml`, or every job dies at install, and `ERR_PNPM_OUTDATED_LOCKFILE` masquerades as "everything failing". **Read the lockfile diff before you commit it.** Any resolution step (`pnpm add`, `pnpm remove`, `pnpm install --lockfile-only`) also rewrites the `node@runtime` entry from `version: 22.22.2` and `hasBin: true` to `version: 0.0.0`. That entry is the resolved form of the root `devEngines` pin, the thing that makes every `pnpm` script run Node 22, so restore those two lines by hand and re-check `pnpm install --frozen-lockfile` before committing. This has slipped through twice.
2. CI runs whole-repo Prettier through root `pnpm format:check`, not just lint. The import-sort plugin orders React and external imports before `@mattermix/*` and `@shaders/*`. Run Prettier on changed files before you commit.
2. CI runs whole-repo Prettier through root `pnpm format:check`, not just lint. The import-sort plugin orders React and external imports before `@camp-dev/*` and `@shaders/*`. Run Prettier on changed files before you commit.
3. Visual regression screenshots the canvas itself, through `page.locator('canvas').first()`, not the full page and not the `[data-shader-demo]` container. A change that resizes or repositions the canvas invalidates baselines. A change confined to the control panel's own styling does not.

That wasn't always true. Before the panel moved into a sidebar outside `[data-shader-demo]`, it sat absolutely positioned inside the canvas's bounding box, so any panel change showed up in the shot too. It no longer does, so you can restyle the panel freely without regenerating anything. But `.demo-layout`'s grid columns and padding are CSS that sizes the canvas, so layout changes there still invalidate baselines, and `DemoPoster`'s poster image sits inside `[data-shader-demo]` but outside the canvas, so nothing captures it either way.
Expand Down Expand Up @@ -127,7 +127,7 @@ These rules exist because Shaders doubles as a shader-learning project for its a
6. **`setClearColor` accepts only `Color` in three 0.170 and later.** Convert with `new Color(...)`.
7. **Vitest exits 1 with no test files.** Set `passWithNoTests: true` in per-package configs.
8. **The docs site needs `@shaders/registry` plus `transpilePackages`** to import raw `.tsx` from a workspace dep.
9. **`three/webgpu` references `self` at module load, so it cannot SSR.** Anything that genuinely reaches the renderer needs `next/dynamic` with `{ ssr: false }`, and all eight component pages load their `scene.tsx` that way. Scalar code that merely ships in the same package does not, and each piece has an import path that never pulls in three: CPU color math at `@mattermix/shaders/color`, and `useDisplayGamut` at `@mattermix/shaders-react/gamut`. A `no-restricted-imports` rule scoped to `apps/docs/**` rejects both roots for those names, so the wrong import fails at lint rather than at render, and each subpath carries a `// @vitest-environment node` test that throws if three creeps back into its graph. Reach for a subpath before you reach for `ssr: false`.
9. **`three/webgpu` references `self` at module load, so it cannot SSR.** Anything that genuinely reaches the renderer needs `next/dynamic` with `{ ssr: false }`, and all eight component pages load their `scene.tsx` that way. Scalar code that merely ships in the same package does not, and each piece has an import path that never pulls in three: CPU color math at `@camp-dev/shaders/color`, and `useDisplayGamut` at `@camp-dev/shaders-react/gamut`. A `no-restricted-imports` rule scoped to `apps/docs/**` rejects both roots for those names, so the wrong import fails at lint rather than at render, and each subpath carries a `// @vitest-environment node` test that throws if three creeps back into its graph. Reach for a subpath before you reach for `ssr: false`.
10. **`tweakpane@4` ships a broken `@tweakpane/core` reference.** Add published `@tweakpane/core` 2.x as a devDep for typecheck.
11. **Consume vec-typed `uniform(...)` as an argument, not a chained receiver, in TSL math.** `uv().sub(cursorUniform)` works. Chaining methods off a raw vec2 or vec3 uniform node silently produces wrong GPU values despite typechecking. Build expressions from `uv()` and `vec2(...)`, and pass vec uniforms as args. Scalar float uniforms are safe as chained receivers. wave-lines chains them throughout and seven visual gates validated it.
12. **three ships two standalone bundles**, `three.module.js` and `three.webgpu.js`. Importing both duplicates three core, which shows up as `Cannot read properties of undefined (reading 'usedTimes')` on dispose. Alias all three subpaths to the webgpu bundle. See `apps/docs/next.config.ts`.
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2026 Hunter Garrett / Mattermix
Copyright (c) 2026 Hunter Garrett / camp.dev

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

React shader components powered by WebGPU and Three.js TSL.

> **Status:** v0.1.0 shipped to npm. `npm install -D @mattermix/shaders-cli && npx shaders-cli init && npx shaders-cli add linear-gradient` to scaffold your first component.
> **Status:** v0.1.0 shipped to npm. `npm install -D @camp-dev/shaders-cli && npx shaders-cli init && npx shaders-cli add linear-gradient` to scaffold your first component.

## What is Shaders?

Expand All @@ -16,9 +16,9 @@ apps/
└── playground/ # @shaders/playground — Vite app with M1 manual harnesses

packages/
├── shaders/ # @mattermix/shaders — engine: TSL primitives, renderer, scheduler
├── shaders-react/ # @mattermix/shaders-react — React binding
└── shaders-cli/ # @mattermix/shaders-cli — copy-paste CLI
├── shaders/ # @camp-dev/shaders — engine: TSL primitives, renderer, scheduler
├── shaders-react/ # @camp-dev/shaders-react — React binding
└── shaders-cli/ # @camp-dev/shaders-cli — copy-paste CLI

registry/ # @shaders/registry — Tier 1 component source files (CLI consumes)

Expand All @@ -41,7 +41,7 @@ pnpm install
pnpm build # build all packages + apps
pnpm typecheck # typecheck all packages + apps
pnpm lint # lint all packages + apps
pnpm test # run all tests (Vitest in @mattermix/shaders)
pnpm test # run all tests (Vitest in @camp-dev/shaders)

# Live shader demo
pnpm --filter @shaders/docs dev # Next.js docs at http://localhost:3000
Expand All @@ -54,7 +54,7 @@ pnpm --filter @shaders/playground dev # Vite at http://localhost:5173

- ✅ **Milestone 0** — Repo bootstrap
- ✅ **Milestone 1** — Vertical slice: `<LinearGradient>` end-to-end
- ✅ **Milestone 2** — `@mattermix/shaders-cli` (copy-paste delivery)
- ✅ **Milestone 2** — `@camp-dev/shaders-cli` (copy-paste delivery)
- ✅ **Milestone 3** — The other 5 v1 components (MeshGradient, Aurora, DotField, NoiseField, Waves)
- ✅ **Milestone 4** — Docs site polish
- ✅ **Milestone 5** — Performance, testing, accessibility
Expand Down
Loading
Loading