feat: TSL (Three Shading Language) support#57
Conversation
Implements discriminated union on `language` field throughout schema, registry, CLI, MCP, and playground to support TSL shaders alongside GLSL. Schema (0.1.0 → 0.2.0): - Discriminated union: GLSL (files: vertex+fragment) / TSL (tslEntry) - Add `node-material` to compatibility material enum - Language defaults to "glsl" for backward compatibility Registry (0.1.0 → 0.2.0): - Index entries include `language` field - Bundles: GLSL (vertexSource+fragmentSource) / TSL (tslSource) - Builder handles both manifest shapes CLI: - `add` writes source.ts for TSL, vertex+fragment.glsl for GLSL - `search` gains `language` filter MCP: - Tools updated with language/tslSource parameters - search_shaders, create_playground, update_shader accept language Playground: - Session types: language, tslSource, structuredErrors fields - DB migration: shader_language, tsl_source, structured_errors_json - API routes handle TSL create/update/errors - UI: language-aware tabs (source.ts vs vertex/fragment.glsl) - Canvas: TSL placeholder (WebGPU preview in follow-up) Corpus: - First TSL shader: tsl-gradient-wave (animated gradient with NodeMaterial) - Existing GLSL shaders bumped to schemaVersion 0.2.0 Closes #56 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Review findings to fix before merge:
Right now the contracts say TSL playground support exists, but the implementation is still stubbed. That is fine as a follow-up branch, but not fine as merged behavior under the current API/MCP surface.
For TSL, structured errors are the important format. If we add them in the web layer but strip them in MCP, agent consumers still cannot handle parse/runtime/material-build failures properly.
Either the CLI must preserve recipe paths, or the recipe code needs to match the flattened output layout.
That keeps the invalid-state problem we explicitly wanted to remove. I ran -- |
|
All four issues addressed. Here's what changed across 11 files: 1. TSL playground contracts are now honest
2. Structured TSL errors flow through MCP
3. CLI
4. Session model is a real discriminated union
— Claude Code (Opus 4.6) |
|
Follow-up review status: I revalidated the requested fixes locally against the current branch state. What is now covered:
Verification completed locally:
These all pass on the updated branch state. Once the follow-up changes are committed and pushed to this PR, it should be ready for re-review. -- |
Thorough review of PR #57 — current branch stateI've reviewed all 27 changed files in the PR diff plus the follow-up fixes. What's goodDiscriminated union is properly enforced top-to-bottom. Validation is explicit, not silent. Playground DB test coverage is comprehensive. Structured errors flow end-to-end. Web DB → web API → MCP handlers → MCP tool response. The Recipe Issues to consider1. PlaygroundCanvas loads Three.js for TSL sessions (low priority)
if (props.language === 'tsl') {
setLoading(false)
return
}
let THREE: THREE
try {
THREE = await import('three')
// ...When WebGPU preview is added later, it'll need 2.
3.
4. No
5. MCP When an agent calls VerdictThe four original review issues are resolved. The validation hardening and DB test coverage are solid additions. The remaining items above are all low-priority and none block merge. Ship it. — Claude Code (Opus 4.6) |
Post-merge follow-up: two additional issues found and fixedAfter the merge, a deeper review surfaced two issues not caught in the original review. Both are now fixed on 1. High: Web detail page crashes for TSL shaders
Result: Navigating to Fix: Made
2. Medium:
|
|
Follow-up on the remaining coverage gap: I added registry-backed detail-path tests in commit b941469 ( est: cover registry-backed shader detail branches).\n\nWhat changed:\n- Added a test for the registry-backed TSL branch of getShaderDetailFromSource()\n- Added a test for the registry-backed GLSL branch of getShaderDetailFromSource()\n- Used dynamic module import with a mocked etch + temporary REGISTRY_URL so the real production code path is exercised without hitting the network\n\nChecks run:\n- |
Summary
languagefield across schema, registry, CLI, MCP, and playground0.1.0→0.2.0and registry format from0.1.0→0.2.0tsl-gradient-wave)Schema (
packages/schema)files(vertex + fragment), TSL manifests havetslEntrylanguagedefaults to"glsl"via preprocessing for backward compatibilitynode-materialto compatibility material enumRegistry (
scripts/build-registry.ts+packages/cli/src/registry-types.ts)languagefieldvertexSource/fragmentSource, TSL hastslSourceCLI (
packages/cli)addwritessource.tsfor TSL shaders,vertex.glsl/fragment.glslfor GLSLsearchgains alanguagefilter optionMCP (
packages/mcp)search_shadersacceptslanguagefiltercreate_playgroundacceptslanguageandtslSourceupdate_shaderacceptstslSourcePlayground (
apps/web)language,tslSource,structuredErrors(discriminated error union)shader_language,tsl_source,structured_errors_jsoncolumnssource.tsfor TSL,vertex.glsl/fragment.glslfor GLSL), language badgeCorpus
tsl-gradient-wave— animated gradient usingNodeMaterialandcreateMaterial()contractschemaVersion: "0.2.0"with explicit"language": "glsl"Out of scope (follow-up)
tsl-fundamentals,tsl-patterns)Test plan
tslSourcewithcreateMaterialfunctionbun run checkpasses (test + typecheck + validate:shaders + build:web)Closes #56
🤖 Generated with Claude Code