Create a new asset pipeline lesson. This is a hybrid track — the pipeline
orchestrator is Python, performance-critical processing uses compiled C tools
(meshoptimizer, MikkTSpace), and procedural geometry lives in a header-only C
library (common/shapes/forge_shapes.h).
The goal is not just pedagogical. Every library, tool, and pipeline
component built in an asset lesson must be production-quality — well-tested,
documented, and designed for reuse beyond the lesson. The project's own
PLAN.md has a "Project Integration" section where forge-gpu's existing
assets (models, textures, skyboxes) are processed through the pipeline we
build. So the pipeline, plugins, and C tools are not toy examples scoped to a
single lesson — they are the actual tooling this project depends on.
Concretely this means:
- Libraries and tools are shared, not lesson-local. Python code goes in
pipeline/, C libraries go in common/, C tools go in tools/. The
lesson directory contains the walkthrough, not the implementation.
- Test thoroughly. Every module gets a test suite (
tests/pipeline/ for
Python, tests/test_*.c for C). Edge cases, error paths, and realistic
inputs — not just happy-path smoke tests.
- Design for integration. The Python pipeline will process forge-gpu's
own models and textures. The C mesh tool will be invoked by the pipeline
as a subprocess. The shapes library is already used by GPU and physics
lessons. Build APIs that work for real projects.
- Don't cut corners for pedagogy. If the correct approach requires more
code, write more code. Simplifying for the lesson at the cost of
correctness or reusability defeats the purpose.
When to use this skill:
- You need to teach asset import, processing, or optimization concepts
- A learner wants to build tooling that transforms raw art into GPU-ready formats
- The lesson involves texture compression, mesh optimization, or asset bundling
- The lesson adds a web UI for browsing, previewing, or configuring assets
- The lesson creates procedural geometry from parametric equations
- The lesson integrates third-party C libraries (meshoptimizer, MikkTSpace)
Smart behavior:
- Before creating a lesson, check if an existing asset lesson already covers it
- Asset lessons are tool-building lessons — every concept must produce a working
CLI command, C tool, library, or web page
- Focus on why each processing step matters for GPU performance
- Cross-reference GPU lessons that consume the processed assets
- Determine the lesson type (Python, C tool, or C library) before scaffolding
Arguments
The user (or you) can provide:
- Number: two-digit lesson number (e.g. 01, 02)
- Topic name: kebab-case (e.g. pipeline-scaffold, texture-processing)
- Description: what this teaches (e.g. "Plugin discovery, CLI entry point, TOML config")
If any are missing, infer from context or ask.
Lesson Types
The asset pipeline track has three lesson types. Determine which type applies
before scaffolding.
Type A: Python lessons
Pipeline scaffold, texture processing, asset bundles, web frontend. These add
functionality to the shared pipeline/ package at the repo root (not
lesson-local code). The lesson directory contains only the README, diagrams,
example config, and sample assets.
Directory structure:
pipeline/ # shared library (repo root) — code goes HERE
__init__.py
__main__.py
config.py, plugin.py, scanner.py, ...
plugins/
<type>.py # built-in plugins grow lesson by lesson
tests/
pipeline/ # tests for the shared library
test_<module>.py
lessons/assets/NN-topic-name/
README.md # lesson walkthrough pointing at pipeline/ code
pipeline.toml # example config for hands-on testing
assets/ # sample source files, diagrams
Not added to CMakeLists.txt — Python projects are not C targets.
pyproject.toml is at the repo root — one package for the whole pipeline.
Type B: C tool lessons
Mesh processing with third-party C libraries (meshoptimizer, MikkTSpace). The
C tool is a standalone executable that the Python pipeline invokes as a
subprocess.
Directory structure:
lessons/assets/NN-topic-name/
README.md
main.c # standalone C tool
CMakeLists.txt # builds the tool, fetches dependencies
tests/
test_<tool>.c # C test suite
Added to CMakeLists.txt — C tools need a build target. Add under an
"Asset Pipeline Lessons" section (create it if needed, after Physics Lessons
or at the end before Tests).
Type C: C library lessons
Procedural geometry and other header-only libraries that live in common/.
These produce a library, a test suite, and optionally a GPU lesson that
renders the output.
Directory structure:
common/<lib>/
forge_<lib>.h # header-only library
README.md # API reference
lessons/assets/NN-topic-name/
README.md # lesson walkthrough (may also have a GPU demo)
PLAN.md # main.c decomposition (if GPU demo included)
main.c # GPU showcase program (optional)
CMakeLists.txt
shaders/ # if GPU demo
assets/
tests/
test_<lib>.c # comprehensive test suite
Added to CMakeLists.txt — register the test target and any GPU demo.
Steps
1. Analyze what's needed
- Determine lesson type: Python (A), C tool (B), or C library (C)?
- Check existing asset lessons: Is there already a lesson for this topic?
- Identify the scope: What specific pipeline concepts does this lesson cover?
- Find cross-references: Which GPU/engine/math lessons relate?
- Check PLAN.md: Where does this lesson fit in the asset pipeline track?
2. Create the lesson directory
Follow the directory structure for the determined lesson type (A, B, or C).
3. Create the lesson content
For Python lessons (Type A)
Package conventions:
- Python 3.10+ — Use modern Python features (type hints, match statements,
dataclasses, pathlib)
- CLI: Use
argparse or click for command-line interface
- Config: TOML for project/asset configuration (
tomllib in 3.11+, or
tomli as fallback)
- Testing: pytest for unit tests
- Naming:
snake_case for modules and functions, PascalCase for classes
- No global state — Pass configuration explicitly
Create pyproject.toml:
[project]
name = "forge-asset-pipeline"
version = "0.1.0"
description = "Asset processing pipeline for forge-gpu"
requires-python = ">=3.10"
dependencies = [
# Add per-lesson dependencies here
]
[project.optional-dependencies]
dev = [
"pytest>=7.0",
"ruff>=0.4",
]
[project.scripts]
forge-pipeline = "pipeline.__main__:main"
For C tool lessons (Type B)
- Follow all forge-gpu C conventions (C99, naming, error handling)
- Use
FetchContent to pull third-party libraries (meshoptimizer, MikkTSpace)
- Build a standalone CLI tool that reads input files and writes output files
- The Python pipeline invokes the tool as a subprocess
- Test with forge-gpu's existing test harness pattern
For C library lessons (Type C)
- Follow the
forge_math.h pattern: header-only, static inline,
thorough inline documentation
- Use
SDL_malloc/SDL_free (not malloc/free)
- Use
forge_math.h types (vec3, vec2, mat4, quat)
- Create a comprehensive test suite following
tests/test_math.c pattern
- Optionally include a GPU demo that renders the library output
- For files over 800 lines, use the chunked-write pattern (mandatory)
4. Create README.md
Structure varies by lesson type but always includes:
- What you'll learn (bullet list)
- Result (screenshot, CLI output, or demo)
- Main explanation with diagrams
- Code walkthrough
- Key concepts
- Cross-references to other tracks
- Exercises
- Further reading
5. Update project files
README.md (root): Add a row to the asset lessons table
lessons/assets/README.md: Add a row to the lessons table
PLAN.md: Check off the asset lesson entry
CMakeLists.txt (root): Add targets for C tools/libraries (Types B and C
only — Python lessons are not registered here)
6. Cross-reference other lessons
- Find related GPU lessons: Which rendering features consume these assets?
- Find related engine lessons: Build systems, dependency management
- Find related math lessons: Vectors, parametric equations, trigonometry
- Update those lesson READMEs: Add cross-reference notes
- Update asset lesson README: List related lessons in "Where it connects"
7. Test
Python lessons:
uv sync --extra dev
uv run pytest tests/pipeline/
uv run ruff check pipeline/
uv run ruff format --check pipeline/
C tool/library lessons:
cmake -B build
cmake --build build --config Debug --target <test-target>
ctest --test-dir build -R <test-name>
Use a Task agent with model: "haiku" for build commands per project
conventions.
8. Run markdown linting
npx markdownlint-cli2 "**/*.md"
Asset Lesson Conventions
Scope
- Core pipeline (Python) — CLI scaffold, plugin discovery, configuration,
scanning, fingerprinting
- Texture processing (Python) — Resize, compress, mipmap generation,
format conversion
- Mesh processing (C tool) — Vertex deduplication, index optimization,
tangent generation (MikkTSpace), LOD generation (meshoptimizer), binary output
- Procedural geometry (C library) — Parametric surface generation, smooth
and flat normals, struct-of-arrays GPU layout
- Asset bundles (Python) — Packing, compression, table of contents,
dependency tracking
- Web frontend (Python) — Asset browser, 3D preview, import settings
editor, scene editor
Python style
- Python 3.10+ with type hints
snake_case for functions and variables, PascalCase for classes
- Docstrings on public functions and classes
pathlib.Path for file paths (not string concatenation)
dataclasses or attrs for structured data
- Lint with Ruff (same config as existing
pyproject.toml in repo root)
C style
Follow the same conventions as all forge-gpu code:
- C99, matching SDL's style
ForgeShapes prefix for public types, forge_shapes_ for functions
(adjust prefix per library)
PascalCase for typedefs, lowercase_snake_case for locals
UPPER_SNAKE_CASE for #define constants
- No magic numbers —
#define or enum everything
SDL_malloc/SDL_free — not malloc/free
- Extensive comments explaining why and purpose
Plugin architecture
The Python pipeline uses a plugin system where each asset type registers a
processor. C tools are invoked as subprocesses by the Python plugin:
import subprocess
from pathlib import Path
class MeshPlugin(AssetPlugin):
"""Mesh processing plugin — invokes compiled C tool."""
name = "mesh"
extensions = [".gltf", ".glb", ".obj"]
def process(self, source: Path, config: dict) -> AssetResult:
result = subprocess.run(
["forge-mesh-tool", str(source), "--output", str(output)],
capture_output=True, text=True
)
if result.returncode != 0:
raise ProcessingError(result.stderr)
return AssetResult(source=source, output=output, metadata={...})
Incremental builds
Every processing step must support incremental builds:
- Fingerprint source files (content hash, not timestamp)
- Compare against cached fingerprints from the last build
- Skip unchanged assets
- Track dependencies — if a texture changes, re-process meshes that
reference it
Configuration
Use TOML for pipeline and per-asset configuration:
# pipeline.toml — project-level config
[pipeline]
source_dir = "assets/raw"
output_dir = "assets/processed"
bundle_dir = "assets/bundles"
[texture]
default_format = "bc7"
max_size = 2048
generate_mipmaps = true
[mesh]
deduplicate = true
generate_tangents = true
lod_levels = [1.0, 0.5, 0.25]
Tone
Asset pipeline lessons should be practical and tool-focused. Pipeline tooling
is infrastructure that enables art and rendering — treat it with the same
rigor as the rendering code it serves. The output of these lessons is not
disposable teaching material; it is production tooling that forge-gpu itself
will use to process its own assets.
- Name the techniques and formats — BC7, KTX2, glTF, meshoptimizer,
MikkTSpace — named tools and formats carry weight and help readers find
documentation
- Show the data flow — Diagrams showing source -> process -> output are
essential for pipeline lessons
- Measure improvement — Show file sizes, load times, or vertex counts
before and after processing
- Connect to GPU — Always explain how the processed output maps to GPU
concepts (texture formats, vertex layouts, draw calls)
- Build for real use — Every API, CLI flag, and config option should work
for a real project, not just the lesson's sample assets
Example: Pipeline Scaffold Lesson (Type A — Python)
- Scope: CLI entry point, plugin discovery, asset scanning, fingerprinting,
TOML configuration
- Create:
lessons/assets/01-pipeline-scaffold/
- Package:
pipeline/ with __main__.py, config.py, scanner.py,
plugin.py
- Program: CLI that scans a directory for assets, fingerprints them, and
reports what would be processed. No actual processing yet.
- README: Explain plugin architecture, fingerprinting, TOML config, CLI
design
- Exercises: Add a new file type to the scanner, implement cache
invalidation, add
--verbose output
Example: Mesh Processing Lesson (Type B — C tool)
- Scope: meshoptimizer for vertex/index optimization, MikkTSpace for
tangent generation, binary output format, LOD generation
- Create:
lessons/assets/03-mesh-processing/
- Tool:
main.c that reads glTF/OBJ, processes with meshoptimizer and
MikkTSpace, writes optimized binary output
- CMake: FetchContent for meshoptimizer and MikkTSpace
- Python plugin:
plugins/mesh.py invokes the compiled tool as subprocess
- README: Explain vertex cache optimization, overdraw optimization, tangent
space, LOD simplification metrics
- Exercises: Add vertex quantization, compare draw call performance before
and after optimization
Example: Procedural Geometry Lesson (Type C — C library)
- Scope:
forge_shapes.h — parametric surface generation (sphere,
icosphere, cylinder, cone, torus, plane, cube, capsule), struct-of-arrays
layout, smooth vs flat normals
- Create:
common/shapes/forge_shapes.h, common/shapes/README.md,
lessons/assets/04-procedural-geometry/, tests/test_shapes.c
- Library: Header-only with
FORGE_SHAPES_IMPLEMENTATION guard
- GPU demo: Five-shape showcase with Blinn-Phong lighting
- Tests: 28 tests covering vertex counts, normals, UVs, winding, memory
- README: Parametric surfaces, slices/stacks, seam duplication, smooth vs
flat normals, struct-of-arrays vs interleaved
When NOT to Create an Asset Lesson
- The topic is covered by an existing asset lesson
- The concept is about GPU rendering only (belongs in a GPU lesson)
- The concept is about C fundamentals only (belongs in an engine lesson)
- The concept is pure math only (belongs in a math lesson)
- The topic is too narrow for a full lesson (add to an existing lesson instead)
In these cases, update existing documentation or plan for later.
Tips
- Start with the CLI — Get the command-line interface working first, then
add processing logic. A well-structured CLI with no-op plugins is a solid
foundation.
- Test with real assets — Use assets from existing GPU lessons as test
inputs. This validates that the pipeline produces output the C code can
actually consume.
- Fingerprint, don't timestamp — Content hashes are deterministic and
portable. Timestamps break on copy, git clone, and CI.
- Show before/after — File size comparisons, vertex count reductions, and
load time improvements make the value of the pipeline concrete.
- Web UI lives in
pipeline/web/ — The frontend is a Vite + TypeScript
project served by the FastAPI backend in pipeline/server.py. The pipeline
is the lesson, not the frontend stack.
- Chunked writes for large C files —
forge_shapes.h and GPU demo
main.c will exceed 800 lines. Use the chunked-write pattern per
.claude/large-file-strategy.md.
1---2name: dev-asset-lesson3description: Add an asset pipeline lesson — hybrid Python + C track for asset processing, procedural geometry, and web frontend4---5
6Create a new asset pipeline lesson. This is a **hybrid track** — the pipeline
7orchestrator is Python, performance-critical processing uses compiled C tools
8(meshoptimizer, MikkTSpace), and procedural geometry lives in a header-only C
9library (`common/shapes/forge_shapes.h`).
10
11**The goal is not just pedagogical.** Every library, tool, and pipeline
12component built in an asset lesson must be production-quality — well-tested,
13documented, and designed for reuse beyond the lesson. The project's own
14`PLAN.md` has a "Project Integration" section where forge-gpu's existing
15assets (models, textures, skyboxes) are processed through the pipeline we
16build. So the pipeline, plugins, and C tools are not toy examples scoped to a
17single lesson — they are the actual tooling this project depends on.
18
19Concretely this means:
20
21- **Libraries and tools are shared, not lesson-local.** Python code goes in
22 `pipeline/`, C libraries go in `common/`, C tools go in `tools/`. The
23 lesson directory contains the walkthrough, not the implementation.
24- **Test thoroughly.** Every module gets a test suite (`tests/pipeline/` for
25 Python, `tests/test_*.c` for C). Edge cases, error paths, and realistic
26 inputs — not just happy-path smoke tests.
27- **Design for integration.** The Python pipeline will process forge-gpu's
28 own models and textures. The C mesh tool will be invoked by the pipeline
29 as a subprocess. The shapes library is already used by GPU and physics
30 lessons. Build APIs that work for real projects.
31- **Don't cut corners for pedagogy.** If the correct approach requires more
32 code, write more code. Simplifying for the lesson at the cost of
33 correctness or reusability defeats the purpose.
34
35**When to use this skill:**
36
37- You need to teach asset import, processing, or optimization concepts
38- A learner wants to build tooling that transforms raw art into GPU-ready formats
39- The lesson involves texture compression, mesh optimization, or asset bundling
40- The lesson adds a web UI for browsing, previewing, or configuring assets
41- The lesson creates procedural geometry from parametric equations
42- The lesson integrates third-party C libraries (meshoptimizer, MikkTSpace)
43
44**Smart behavior:**
45
46- Before creating a lesson, check if an existing asset lesson already covers it
47- Asset lessons are tool-building lessons — every concept must produce a working
48 CLI command, C tool, library, or web page
49- Focus on *why* each processing step matters for GPU performance
50- Cross-reference GPU lessons that consume the processed assets
51- Determine the lesson type (Python, C tool, or C library) before scaffolding
52
53## Arguments
54
55The user (or you) can provide:
56
57- **Number**: two-digit lesson number (e.g. 01, 02)
58- **Topic name**: kebab-case (e.g. pipeline-scaffold, texture-processing)
59- **Description**: what this teaches (e.g. "Plugin discovery, CLI entry point, TOML config")
60
61If any are missing, infer from context or ask.
62
63## Lesson Types
64
65The asset pipeline track has three lesson types. Determine which type applies
66before scaffolding.
67
68### Type A: Python lessons
69
70Pipeline scaffold, texture processing, asset bundles, web frontend. These add
71functionality to the **shared `pipeline/` package** at the repo root (not
72lesson-local code). The lesson directory contains only the README, diagrams,
73example config, and sample assets.
74
75**Directory structure:**
76
77```text
78pipeline/ # shared library (repo root) — code goes HERE
79 __init__.py
80 __main__.py
81 config.py, plugin.py, scanner.py, ...
82 plugins/
83 <type>.py # built-in plugins grow lesson by lesson
84tests/
85 pipeline/ # tests for the shared library
86 test_<module>.py
87lessons/assets/NN-topic-name/
88 README.md # lesson walkthrough pointing at pipeline/ code
89 pipeline.toml # example config for hands-on testing
90 assets/ # sample source files, diagrams
91```
92
93**Not added to CMakeLists.txt** — Python projects are not C targets.
94**`pyproject.toml` is at the repo root** — one package for the whole pipeline.
95
96### Type B: C tool lessons
97
98Mesh processing with third-party C libraries (meshoptimizer, MikkTSpace). The
99C tool is a standalone executable that the Python pipeline invokes as a
100subprocess.
101
102**Directory structure:**
103
104```text
105lessons/assets/NN-topic-name/
106 README.md
107 main.c # standalone C tool
108 CMakeLists.txt # builds the tool, fetches dependencies
109 tests/
110 test_<tool>.c # C test suite
111```
112
113**Added to CMakeLists.txt** — C tools need a build target. Add under an
114"Asset Pipeline Lessons" section (create it if needed, after Physics Lessons
115or at the end before Tests).
116
117### Type C: C library lessons
118
119Procedural geometry and other header-only libraries that live in `common/`.
120These produce a library, a test suite, and optionally a GPU lesson that
121renders the output.
122
123**Directory structure:**
124
125```text
126common/<lib>/
127 forge_<lib>.h # header-only library
128 README.md # API reference
129lessons/assets/NN-topic-name/
130 README.md # lesson walkthrough (may also have a GPU demo)
131 PLAN.md # main.c decomposition (if GPU demo included)
132 main.c # GPU showcase program (optional)
133 CMakeLists.txt
134 shaders/ # if GPU demo
135 assets/
136tests/
137 test_<lib>.c # comprehensive test suite
138```
139
140**Added to CMakeLists.txt** — register the test target and any GPU demo.
141
142## Steps
143
144### 1. Analyze what's needed
145
146- **Determine lesson type**: Python (A), C tool (B), or C library (C)?
147- **Check existing asset lessons**: Is there already a lesson for this topic?
148- **Identify the scope**: What specific pipeline concepts does this lesson cover?
149- **Find cross-references**: Which GPU/engine/math lessons relate?
150- **Check PLAN.md**: Where does this lesson fit in the asset pipeline track?
151
152### 2. Create the lesson directory
153
154Follow the directory structure for the determined lesson type (A, B, or C).
155
156### 3. Create the lesson content
157
158#### For Python lessons (Type A)
159
160**Package conventions:**
161
162- **Python 3.10+** — Use modern Python features (type hints, match statements,
163 dataclasses, pathlib)
164- **CLI**: Use `argparse` or `click` for command-line interface
165- **Config**: TOML for project/asset configuration (`tomllib` in 3.11+, or
166 `tomli` as fallback)
167- **Testing**: pytest for unit tests
168- **Naming**: `snake_case` for modules and functions, `PascalCase` for classes
169- **No global state** — Pass configuration explicitly
170
171Create `pyproject.toml`:
172
173```toml
174[project]
175name = "forge-asset-pipeline"
176version = "0.1.0"
177description = "Asset processing pipeline for forge-gpu"
178requires-python = ">=3.10"
179dependencies = [
180 # Add per-lesson dependencies here
181]
182
183[project.optional-dependencies]
184dev = [
185 "pytest>=7.0",
186 "ruff>=0.4",
187]
188
189[project.scripts]
190forge-pipeline = "pipeline.__main__:main"
191```
192
193#### For C tool lessons (Type B)
194
195- Follow all forge-gpu C conventions (C99, naming, error handling)
196- Use `FetchContent` to pull third-party libraries (meshoptimizer, MikkTSpace)
197- Build a standalone CLI tool that reads input files and writes output files
198- The Python pipeline invokes the tool as a subprocess
199- Test with forge-gpu's existing test harness pattern
200
201#### For C library lessons (Type C)
202
203- Follow the `forge_math.h` pattern: header-only, `static inline`,
204 thorough inline documentation
205- Use `SDL_malloc`/`SDL_free` (not `malloc`/`free`)
206- Use `forge_math.h` types (`vec3`, `vec2`, `mat4`, `quat`)
207- Create a comprehensive test suite following `tests/test_math.c` pattern
208- Optionally include a GPU demo that renders the library output
209- For files over 800 lines, use the chunked-write pattern (mandatory)
210
211### 4. Create `README.md`
212
213Structure varies by lesson type but always includes:
214
215- What you'll learn (bullet list)
216- Result (screenshot, CLI output, or demo)
217- Main explanation with diagrams
218- Code walkthrough
219- Key concepts
220- Cross-references to other tracks
221- Exercises
222- Further reading
223
224### 5. Update project files
225
226- **`README.md` (root)**: Add a row to the asset lessons table
227- **`lessons/assets/README.md`**: Add a row to the lessons table
228- **`PLAN.md`**: Check off the asset lesson entry
229- **`CMakeLists.txt` (root)**: Add targets for C tools/libraries (Types B and C
230 only — Python lessons are not registered here)
231
232### 6. Cross-reference other lessons
233
234- **Find related GPU lessons**: Which rendering features consume these assets?
235- **Find related engine lessons**: Build systems, dependency management
236- **Find related math lessons**: Vectors, parametric equations, trigonometry
237- **Update those lesson READMEs**: Add cross-reference notes
238- **Update asset lesson README**: List related lessons in "Where it connects"
239
240### 7. Test
241
242**Python lessons:**
243
244```bash
245uv sync --extra dev
246uv run pytest tests/pipeline/
247uv run ruff check pipeline/
248uv run ruff format --check pipeline/
249```
250
251**C tool/library lessons:**
252
253```bash
254cmake -B build
255cmake --build build --config Debug --target <test-target>
256ctest --test-dir build -R <test-name>
257```
258
259Use a Task agent with `model: "haiku"` for build commands per project
260conventions.
261
262### 8. Run markdown linting
263
264```bash
265npx markdownlint-cli2 "**/*.md"
266```
267
268## Asset Lesson Conventions
269
270### Scope
271
272- **Core pipeline** (Python) — CLI scaffold, plugin discovery, configuration,
273 scanning, fingerprinting
274- **Texture processing** (Python) — Resize, compress, mipmap generation,
275 format conversion
276- **Mesh processing** (C tool) — Vertex deduplication, index optimization,
277 tangent generation (MikkTSpace), LOD generation (meshoptimizer), binary output
278- **Procedural geometry** (C library) — Parametric surface generation, smooth
279 and flat normals, struct-of-arrays GPU layout
280- **Asset bundles** (Python) — Packing, compression, table of contents,
281 dependency tracking
282- **Web frontend** (Python) — Asset browser, 3D preview, import settings
283 editor, scene editor
284
285### Python style
286
287- Python 3.10+ with type hints
288- `snake_case` for functions and variables, `PascalCase` for classes
289- Docstrings on public functions and classes
290- `pathlib.Path` for file paths (not string concatenation)
291- `dataclasses` or `attrs` for structured data
292- Lint with Ruff (same config as existing `pyproject.toml` in repo root)
293
294### C style
295
296Follow the same conventions as all forge-gpu code:
297
298- C99, matching SDL's style
299- `ForgeShapes` prefix for public types, `forge_shapes_` for functions
300 (adjust prefix per library)
301- `PascalCase` for typedefs, `lowercase_snake_case` for locals
302- `UPPER_SNAKE_CASE` for `#define` constants
303- No magic numbers — `#define` or `enum` everything
304- `SDL_malloc`/`SDL_free` — not `malloc`/`free`
305- Extensive comments explaining *why* and *purpose*
306
307### Plugin architecture
308
309The Python pipeline uses a plugin system where each asset type registers a
310processor. C tools are invoked as subprocesses by the Python plugin:
311
312```python
313import subprocess
314from pathlib import Path
315
316class MeshPlugin(AssetPlugin):
317 """Mesh processing plugin — invokes compiled C tool."""
318 name = "mesh"
319 extensions = [".gltf", ".glb", ".obj"]
320
321 def process(self, source: Path, config: dict) -> AssetResult:
322 result = subprocess.run(
323 ["forge-mesh-tool", str(source), "--output", str(output)],
324 capture_output=True, text=True
325 )
326 if result.returncode != 0:
327 raise ProcessingError(result.stderr)
328 return AssetResult(source=source, output=output, metadata={...})
329```
330
331### Incremental builds
332
333Every processing step must support incremental builds:
334
3351. **Fingerprint** source files (content hash, not timestamp)
3362. **Compare** against cached fingerprints from the last build
3373. **Skip** unchanged assets
3384. **Track dependencies** — if a texture changes, re-process meshes that
339 reference it
340
341### Configuration
342
343Use TOML for pipeline and per-asset configuration:
344
345```toml
346# pipeline.toml — project-level config
347[pipeline]
348source_dir = "assets/raw"
349output_dir = "assets/processed"
350bundle_dir = "assets/bundles"
351
352[texture]
353default_format = "bc7"
354max_size = 2048
355generate_mipmaps = true
356
357[mesh]
358deduplicate = true
359generate_tangents = true
360lod_levels = [1.0, 0.5, 0.25]
361```
362
363### Tone
364
365Asset pipeline lessons should be practical and tool-focused. Pipeline tooling
366is infrastructure that enables art and rendering — treat it with the same
367rigor as the rendering code it serves. The output of these lessons is not
368disposable teaching material; it is production tooling that forge-gpu itself
369will use to process its own assets.
370
371- **Name the techniques and formats** — BC7, KTX2, glTF, meshoptimizer,
372 MikkTSpace — named tools and formats carry weight and help readers find
373 documentation
374- **Show the data flow** — Diagrams showing source -> process -> output are
375 essential for pipeline lessons
376- **Measure improvement** — Show file sizes, load times, or vertex counts
377 before and after processing
378- **Connect to GPU** — Always explain how the processed output maps to GPU
379 concepts (texture formats, vertex layouts, draw calls)
380- **Build for real use** — Every API, CLI flag, and config option should work
381 for a real project, not just the lesson's sample assets
382
383## Example: Pipeline Scaffold Lesson (Type A — Python)
384
3851. **Scope**: CLI entry point, plugin discovery, asset scanning, fingerprinting,
386 TOML configuration
3872. **Create**: `lessons/assets/01-pipeline-scaffold/`
3883. **Package**: `pipeline/` with `__main__.py`, `config.py`, `scanner.py`,
389 `plugin.py`
3904. **Program**: CLI that scans a directory for assets, fingerprints them, and
391 reports what would be processed. No actual processing yet.
3925. **README**: Explain plugin architecture, fingerprinting, TOML config, CLI
393 design
3946. **Exercises**: Add a new file type to the scanner, implement cache
395 invalidation, add `--verbose` output
396
397## Example: Mesh Processing Lesson (Type B — C tool)
398
3991. **Scope**: meshoptimizer for vertex/index optimization, MikkTSpace for
400 tangent generation, binary output format, LOD generation
4012. **Create**: `lessons/assets/03-mesh-processing/`
4023. **Tool**: `main.c` that reads glTF/OBJ, processes with meshoptimizer and
403 MikkTSpace, writes optimized binary output
4044. **CMake**: FetchContent for meshoptimizer and MikkTSpace
4055. **Python plugin**: `plugins/mesh.py` invokes the compiled tool as subprocess
4066. **README**: Explain vertex cache optimization, overdraw optimization, tangent
407 space, LOD simplification metrics
4087. **Exercises**: Add vertex quantization, compare draw call performance before
409 and after optimization
410
411## Example: Procedural Geometry Lesson (Type C — C library)
412
4131. **Scope**: `forge_shapes.h` — parametric surface generation (sphere,
414 icosphere, cylinder, cone, torus, plane, cube, capsule), struct-of-arrays
415 layout, smooth vs flat normals
4162. **Create**: `common/shapes/forge_shapes.h`, `common/shapes/README.md`,
417 `lessons/assets/04-procedural-geometry/`, `tests/test_shapes.c`
4183. **Library**: Header-only with `FORGE_SHAPES_IMPLEMENTATION` guard
4194. **GPU demo**: Five-shape showcase with Blinn-Phong lighting
4205. **Tests**: 28 tests covering vertex counts, normals, UVs, winding, memory
4216. **README**: Parametric surfaces, slices/stacks, seam duplication, smooth vs
422 flat normals, struct-of-arrays vs interleaved
423
424## When NOT to Create an Asset Lesson
425
426- The topic is covered by an existing asset lesson
427- The concept is about GPU rendering only (belongs in a GPU lesson)
428- The concept is about C fundamentals only (belongs in an engine lesson)
429- The concept is pure math only (belongs in a math lesson)
430- The topic is too narrow for a full lesson (add to an existing lesson instead)
431
432In these cases, update existing documentation or plan for later.
433
434## Tips
435
436- **Start with the CLI** — Get the command-line interface working first, then
437 add processing logic. A well-structured CLI with no-op plugins is a solid
438 foundation.
439- **Test with real assets** — Use assets from existing GPU lessons as test
440 inputs. This validates that the pipeline produces output the C code can
441 actually consume.
442- **Fingerprint, don't timestamp** — Content hashes are deterministic and
443 portable. Timestamps break on copy, git clone, and CI.
444- **Show before/after** — File size comparisons, vertex count reductions, and
445 load time improvements make the value of the pipeline concrete.
446- **Web UI lives in `pipeline/web/`** — The frontend is a Vite + TypeScript
447 project served by the FastAPI backend in `pipeline/server.py`. The pipeline
448 is the lesson, not the frontend stack.
449- **Chunked writes for large C files** — `forge_shapes.h` and GPU demo
450 `main.c` will exceed 800 lines. Use the chunked-write pattern per
451 `.claude/large-file-strategy.md`.