원클릭으로
dev-audio-lesson
Add an audio lesson — sound playback, mixing, spatial audio, DSP effects, with SDL GPU scenes and forge UI
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Add an audio lesson — sound playback, mixing, spatial audio, DSP effects, with SDL GPU scenes and forge UI
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Add PBR texture loading with separate roughness/metallic support to an SDL GPU project using forge_scene.h
Add Cook-Torrance PBR shading with GGX, Schlick-GGX, and Schlick Fresnel to an SDL GPU project alongside forge_scene.h
Add instanced grass rendering with segmented blades, wind animation, LOD density rings, and terrain LOD with geomorphing to an SDL GPU project
Add procedural noise texture generation to the asset pipeline — C tool, Python plugin, web UI with live preview
Add an asset pipeline lesson — hybrid Python + C track for asset processing, procedural geometry, and web frontend
Run a quality review pass on a lesson before publishing, catching recurring issues found across project PR history
| name | dev-audio-lesson |
| description | Add an audio lesson — sound playback, mixing, spatial audio, DSP effects, with SDL GPU scenes and forge UI |
| argument-hint | [number] [topic-name] [description] |
Every audio lesson produces two things: library code and a demo
program. The library — common/audio/forge_audio.h — is the primary
deliverable. The lessons teach concepts; the library is what remains when the
learning is done. It must be correct, efficient, tested, and safe. The demo
program visualizes and controls the audio in action, rendered with SDL GPU
and controlled through forge UI panels.
When to use this skill:
common/audio/forge_audio.hSmart behavior:
common/shapes/forge_shapes.h — never write
inline geometry generation functionsThe user (or you) can provide:
If any are missing, infer from context or ask.
common/audio/: Does relevant library code already exist?common/ui/: Does the UI library provide the widgets needed for
audio controls? If a required widget is missing, note it.lessons/audio/NN-topic-name/
With subdirectories:
lessons/audio/NN-topic-name/
main.c
CMakeLists.txt
README.md
audio.conf (gitignored — local path to audio files)
assets/
screenshot.png (lesson screenshot — checked in)
Baseline rendering shaders (shadow, scene, grid, sky, UI) are provided by
forge_scene.h — no per-lesson copies needed. If the lesson introduces a
topic-specific shader (e.g. a waveform visualization pass), add a shaders/
subdirectory for those files only.
Every audio lesson adds to common/audio/forge_audio.h. This is not
optional — it is the primary deliverable. The demo program exists to exercise
and visualize the library; the library is what ships.
For the first audio lesson, create the file. For subsequent lessons, extend it. Design the API before writing the demo. The demo calls the library — never the reverse.
Correctness:
Thread safety:
Performance:
float for all audio processing. Convert to/from integer formats only
at the SDL boundary.Numerical safety:
[-1.0f, 1.0f] before delivery to prevent
clipping distortion beyond what the user intends.Header-only implementation:
static inline for all functions — no separate .c compilation unit#ifndef FORGE_AUDIO_H / #define / #endif"math/forge_math.h", and standard C headersDocumentation (every function, no exceptions):
/* Load a WAV file into an audio buffer.
*
* Reads the WAV file at the given path using SDL_LoadWAV and converts
* it to the specified format. The returned buffer owns its sample data
* and must be freed with forge_audio_buffer_free().
*
* Parameters:
* path — file path to the WAV file (must not be NULL)
* spec — desired output format (sample rate, channels, format)
*
* Returns:
* ForgeAudioBuffer with sample data, or a zero-initialized struct
* on failure (check .data != NULL).
*
* Usage:
* ForgeAudioBuffer buf = forge_audio_load_wav("/path/to/audio/click.wav", spec);
* if (!buf.data) { SDL_Log("Failed to load WAV"); return; }
*
* See: Audio Lesson 01 — Audio Basics
* Ref: SDL3 documentation, SDL_LoadWAV
*/
Every doc comment must include:
Naming:
forge_audio_verb_noun() — e.g. forge_audio_init(),
forge_audio_load_wav(), forge_audio_play_oneshot()ForgeAudioNoun — e.g. ForgeAudioBuffer, ForgeAudioSource,
ForgeAudioMixer, ForgeAudioListenerFORGE_AUDIO_UPPER — e.g. FORGE_AUDIO_MAX_SOURCESCore types to establish in Lesson 01:
#ifndef FORGE_AUDIO_H
#define FORGE_AUDIO_H
#include <SDL3/SDL.h>
#include "math/forge_math.h"
/* --- Audio buffer (decoded sample data) --------------------------------- */
typedef struct ForgeAudioBuffer {
float *data; /* interleaved float samples */
int sample_count; /* total samples (frames * channels) */
int channels; /* 1 = mono, 2 = stereo */
int sample_rate; /* Hz — typically 44100 or 48000 */
} ForgeAudioBuffer;
/* --- Audio source (a playing instance) ---------------------------------- */
typedef struct ForgeAudioSource {
const ForgeAudioBuffer *buffer; /* sample data (not owned) */
int cursor; /* current read position in samples */
float volume; /* linear gain [0..1] */
float pan; /* stereo pan [-1..1], 0 = center */
bool looping; /* true = restart at end of buffer */
bool playing; /* true = actively producing samples */
} ForgeAudioSource;
/* ... functions grow lesson by lesson ... */
#endif /* FORGE_AUDIO_H */
The audio library is tested independently of the demo program. Tests validate
correctness, edge cases, and determinism. Every function added to
forge_audio.h must have corresponding tests in tests/audio/test_audio.c.
Test categories (every function must have all applicable categories):
Basic correctness — Known inputs produce expected outputs. For audio processing functions, verify output samples against hand-computed values.
Edge cases — Empty buffers, zero-length audio, single-sample buffers, zero volume, maximum volume, out-of-range panning values, mismatched sample rates.
No artifacts — Volume transitions produce no clicks (verify samples
are continuous). Looping produces seamless playback (verify loop-point
samples match). Mixing does not overflow [-1, 1] without explicit
clipping.
Determinism — Two identical sources with identical parameters produce bit-identical output.
Thread safety — Parameter changes during playback do not crash. Verify with single-threaded simulation (no need to test actual SDL threads in unit tests).
Test infrastructure:
tests/audio/test_audio.cCMakeLists.txt as test_audioASSERT_NEAR / test macros as tests/math/test_math.ccmake --build build --target test_audio && ctest --test-dir build -R audiomain.c)A focused C program that demonstrates audio concepts with both audible output and visual feedback using SDL GPU and forge UI.
MANDATORY: Use forge_scene.h for the rendering baseline. The scene
library provides Blinn-Phong lighting, shadow mapping, grid floor, sky
gradient, FPS camera, and UI in a single forge_scene_init() call. This
eliminates hundreds of lines of rendering boilerplate and lets the lesson
focus on audio. See the forge-scene-renderer skill for the full API.
Every audio lesson MUST include these features:
SDL GPU rendered scene via forge_scene.h — A 3D scene providing
visual context for the audio. For spatial audio lessons, this means visible
sound source positions in the scene. For fundamentals lessons, a simple
scene with visual feedback (waveform visualization, VU meters as colored
geometry) is sufficient. The rendering baseline (Blinn-Phong, grid, shadow
map, depth buffer, sRGB swapchain, sky) is provided by forge_scene.h.
First-person camera — Provided by forge_scene.h. The camera position
(accessible via forge_scene_cam_pos()) doubles as the audio listener
position for spatial audio lessons.
Forge UI panel — Provided by forge_scene.h via
forge_scene_begin_ui() / forge_scene_end_ui(). Every lesson must have
at least:
Capture support — forge_capture.h integration (when FORGE_CAPTURE
defined) via scripts/capture_lesson.py.
Audio requirements:
SDL_AudioStream.
Create the stream at init, feed samples in the iterate callback or via
SDL's audio device callback.audio.conf file (gitignored) that points
to a local directory containing the user's audio files. See step 7 for the
full config workflow.Simulation controls:
| Key | Action |
|---|---|
| R | Reset / replay audio from start |
| P | Pause / resume audio playback |
| 1–9 | Trigger sound effects (where applicable) |
| +/- | Adjust master volume |
Scene geometry via forge_shapes.h (MANDATORY):
All scene geometry must come from common/shapes/forge_shapes.h. Use
spheres or icospheres for sound source positions, cones for directional
sources. Never write inline geometry generation functions.
Template structure:
/*
* Audio Lesson NN — Topic Name
*
* Demonstrates: [what this shows]
*
* Controls:
* WASD / Arrow keys — move camera (listener position)
* Mouse — look around
* R — reset / replay audio
* P — pause / resume
* 1–9 — trigger sound effects
* +/- — adjust master volume
* Escape — release mouse / quit
*
* SPDX-License-Identifier: Zlib
*/
#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <stddef.h>
#include "math/forge_math.h"
#include "audio/forge_audio.h"
#include "shapes/forge_shapes.h"
#define FORGE_SCENE_IMPLEMENTATION
#include "scene/forge_scene.h"
/* ── Constants ────────────────────────────────────────────────────── */
#define AUDIO_SAMPLE_RATE 48000
/* ── Types ────────────────────────────────────────────────────────── */
typedef struct app_state {
ForgeScene scene; /* rendering, camera, shadow map, grid, sky, UI */
/* GPU resources — app-owned geometry */
SDL_GPUBuffer *sphere_vb, *sphere_ib;
int sphere_index_count;
/* Audio state — lesson-specific */
SDL_AudioStream *audio_stream; /* SDL audio output stream */
/* ForgeAudioBuffer buffers[N]; */
/* ForgeAudioSource sources[N]; */
float master_volume; /* linear gain [0..1] */
bool audio_paused; /* true = audio playback frozen */
} app_state;
Init pattern:
SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv)
{
app_state *state = SDL_calloc(1, sizeof(*state));
if (!state) return SDL_APP_FAILURE;
*appstate = state;
ForgeSceneConfig cfg = forge_scene_default_config("Audio NN — Topic");
cfg.cam_start_pos = vec3_create(0.0f, 4.0f, 12.0f);
cfg.font_path = "assets/fonts/liberation_mono/LiberationMono-Regular.ttf";
if (!forge_scene_init(&state->scene, &cfg, argc, argv))
return SDL_APP_FAILURE;
state->master_volume = 1.0f;
/* Read audio directory from audio.conf */
char audio_dir[512];
if (!read_audio_conf("audio.conf", audio_dir, sizeof(audio_dir))) {
SDL_Log("audio.conf not found or not configured.");
SDL_Log("See the lesson README for setup instructions.");
return SDL_APP_FAILURE;
}
/* Load audio files from user's directory, set up SDL audio stream,
* upload shapes ... */
return SDL_APP_CONTINUE;
}
Iterate pattern (camera position as listener):
SDL_AppResult SDL_AppIterate(void *appstate)
{
app_state *state = appstate;
ForgeScene *s = &state->scene;
if (!forge_scene_begin_frame(s)) return SDL_APP_CONTINUE;
/* Use camera position as audio listener */
vec3 listener_pos = forge_scene_cam_pos(s);
/* Shadow pass */
forge_scene_begin_shadow_pass(s);
/* forge_scene_draw_shadow_mesh(s, vb, ib, count, model); */
forge_scene_end_shadow_pass(s);
/* Main pass */
forge_scene_begin_main_pass(s);
/* Draw sound source markers as colored spheres */
/* forge_scene_draw_mesh(s, vb, ib, count, model, color); */
forge_scene_draw_grid(s);
forge_scene_end_main_pass(s);
/* UI pass — audio controls */
float mx, my;
Uint32 buttons = SDL_GetMouseState(&mx, &my);
forge_scene_begin_ui(s, mx, my, (buttons & SDL_BUTTON_LMASK) != 0);
/* forge_ui_* slider/button calls for volume, pan, effects ... */
forge_scene_end_ui(s);
return forge_scene_end_frame(s);
}
The baseline shaders (scene, grid, shadow, sky, UI) are compiled into
forge_scene.h — no per-lesson copies needed. If the lesson introduces a
topic-specific shader (e.g. a waveform or spectrum visualization pass),
add those files to shaders/ and compile them:
python scripts/compile_shaders.py audio/NN-topic-name
Most audio lessons need no lesson-specific shaders at all.
CMakeLists.txtadd_executable(NN-topic-name WIN32 main.c)
target_include_directories(NN-topic-name PRIVATE ${FORGE_COMMON_DIR})
target_link_libraries(NN-topic-name PRIVATE SDL3::SDL3
$<$<NOT:$<C_COMPILER_ID:MSVC>>:m>)
forge_target_assets(NN-topic-name)
if(FORGE_CAPTURE)
target_compile_definitions(NN-topic-name PRIVATE FORGE_CAPTURE)
endif()
# Copy SDL3 DLL next to executable (Windows)
if(TARGET SDL3::SDL3-shared)
add_custom_command(TARGET NN-topic-name POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:SDL3::SDL3-shared>
$<TARGET_FILE_DIR:NN-topic-name>
VERBATIM
)
endif()
# Copy audio.conf next to executable (user-local audio file paths)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/audio.conf)
add_custom_command(TARGET NN-topic-name POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/audio.conf
$<TARGET_FILE_DIR:NN-topic-name>/audio.conf
)
endif()
Create forge-assets.toml next to CMakeLists.txt:
[assets]
dirs = [
"fonts/liberation_mono",
]
All assets — fonts, textures, models — come from the pipeline's processed
output via the manifest. NEVER write bespoke CMake copy commands for
fonts or other assets. See
pipeline/README.md
for the full manifest reference.
Audio files are not checked into the repository. Each lesson uses a
gitignored audio.conf file that points to a local directory containing the
user's own audio files. This avoids distributing copyrighted or large binary
assets.
audio.conf fileCreate lessons/audio/NN-topic-name/audio.conf:
# Audio file configuration for Audio Lesson NN — Topic Name
#
# This file is gitignored. Point audio_dir to a local directory containing
# audio files for this lesson. See README.md for what types of files work
# best.
#
# Royalty-free audio files can be obtained from sites like:
# freesound.org, pixabay.com/music, opengameart.org, incompetech.com
#
audio_dir = /path/to/your/audio/files
This bare-bones config is created by the developer scaffolding the lesson. It ships with a placeholder path that the user replaces with their own.
audio.conf to .gitignoreEnsure the root .gitignore contains:
# Audio lesson config — local paths to user-supplied audio files
lessons/**/audio.conf
Add this entry if it does not already exist.
Every audio lesson README must have an "Audio files" section (see step 8) that explains:
What types of audio files the lesson needs — be specific about content, not just format. Examples:
Format requirements — WAV preferred, mono or stereo, 16-bit or 32-bit float, 44100 or 48000 Hz. Note any specific requirements (e.g. "must be mono for spatial audio").
Where to find royalty-free audio — Point readers to sources:
How to configure — Tell the reader to edit audio.conf and set
audio_dir to the directory containing their files.
audio.confThe lesson's main.c reads audio.conf at startup to find the audio
directory, then loads files from that directory. Add a config-reading helper
to forge_audio.h (or use a local helper if it's lesson-specific):
/* Read the audio_dir path from audio.conf.
* Returns true on success, false if the file is missing or
* the path is the unedited placeholder. */
static bool read_audio_conf(const char *conf_path, char *out_dir, int max_len)
{
SDL_IOStream *io = SDL_IOFromFile(conf_path, "r");
if (!io) return false;
char line[1024];
bool found = false;
Sint64 size = SDL_GetIOSize(io);
if (size > 0 && size < (Sint64)sizeof(line)) {
/* Read entire small file */
size_t bytes_read = SDL_ReadIO(io, line, (size_t)size);
if (bytes_read != (size_t)size) { SDL_CloseIO(io); return false; }
line[bytes_read] = '\0';
/* Parse audio_dir = <path> */
const char *key = "audio_dir";
char *pos = strstr(line, key);
if (pos) {
pos += strlen(key);
while (*pos == ' ' || *pos == '=') pos++;
/* Trim trailing whitespace / newline */
char *end = pos + strlen(pos) - 1;
while (end > pos && (*end == '\n' || *end == '\r' || *end == ' '))
*end-- = '\0';
/* Reject placeholder or empty path */
if (*pos == '\0' || strstr(pos, "/path/to/") || strstr(pos, "\\path\\to\\")) {
SDL_CloseIO(io);
return false;
}
SDL_snprintf(out_dir, max_len, "%s", pos);
found = true;
}
}
SDL_CloseIO(io);
return found;
}
At init time:
char audio_dir[512];
if (!read_audio_conf("audio.conf", audio_dir, sizeof(audio_dir))) {
SDL_Log("audio.conf not found or not configured.");
SDL_Log("Create lessons/audio/NN-topic-name/audio.conf with:");
SDL_Log(" audio_dir = /path/to/your/audio/files");
SDL_Log("See the lesson README for what audio files are needed.");
return SDL_APP_FAILURE;
}
/* Build full paths to specific audio files */
char wav_path[512];
SDL_snprintf(wav_path, sizeof(wav_path), "%s/click.wav", audio_dir);
ForgeAudioBuffer click = forge_audio_load_wav(wav_path, spec);
When creating a lesson, if audio.conf already exists with a valid
audio_dir, scan that directory and help the user choose appropriate files:
.wav, .ogg, .mp3, and .flac files in the directoryffprobe or soxi if available, otherwise just list filenames)If audio.conf does not exist or has the placeholder path, ask the user:
This lesson needs audio files. Please provide a path to a directory
containing audio files (WAV, OGG, MP3, or FLAC).
This lesson needs:
- [specific audio requirements from the lesson design]
Royalty-free audio can be found at freesound.org, pixabay.com, or
opengameart.org.
What is the path to your audio directory?
Then create audio.conf with their answer and proceed with file selection.
The lesson code should reference audio files by well-known names that correspond to their purpose, not opaque filenames. Define constants:
/* Audio file names — the user places files with these names in their
* audio directory, or the lesson maps their chosen files to these names. */
#define AUDIO_FILE_CLICK "click.wav"
#define AUDIO_FILE_AMBIENT "ambient.wav"
#define AUDIO_FILE_MUSIC "music.wav"
The README should list these expected filenames and what each one is for, so the user knows which of their files to use (or rename).
README.mdStructure:
# Audio Lesson NN — Topic Name
[Brief subtitle explaining the audio concept]
## What you'll learn
[Bullet list of audio and implementation concepts covered]
## Result
<!-- TODO: screenshot -->
[Brief description of what the demo shows and sounds like.]

**Controls:**
| Key | Action |
|---|---|
| WASD / Arrows | Move camera (listener position) |
| Mouse | Look around |
| R | Reset / replay audio |
| P | Pause / resume |
| 1–9 | Trigger sound effects |
| +/- | Adjust master volume |
| Escape | Release mouse / quit |
## Audio files
This lesson needs the following audio files. Audio is not included in the
repository — you supply your own files via `audio.conf`.
| Name | Purpose | Requirements |
|---|---|---|
| `click.wav` | One-shot playback demo | Short percussive sound (< 1 s), mono or stereo |
| `ambient.wav` | Looping playback demo | 2–5 s ambient loop, mono or stereo |
**Format:** WAV, 16-bit or 32-bit float, 44100 or 48000 Hz.
**Where to find royalty-free audio:**
- [freesound.org](https://freesound.org) — CC0 and CC-BY samples
- [pixabay.com/sound-effects](https://pixabay.com/sound-effects) — royalty-free
- [opengameart.org](https://opengameart.org) — game-oriented sounds
- [incompetech.com](https://incompetech.com) — Kevin MacLeod music (CC-BY)
**Setup:** Edit `audio.conf` in this lesson directory and set `audio_dir` to
the directory containing your audio files. The program loads files by the
names listed above from that directory.
## The audio
[Main explanation of the audio concepts, with diagrams where helpful.
Use /dev-create-diagram for waveform visualizations, signal flow diagrams,
filter response curves, etc.]
### [Core concept 1]
[Explanation with equations where relevant. For example:]
Linear attenuation reduces volume based on distance from the listener:
$$
\text{gain} = 1 - \frac{d}{d_{\text{max}}}
$$
### [Core concept 2]
[More explanation]
## The code
### Audio initialization
[Explain SDL audio stream setup and buffer management]
### Processing loop
[Walk through the audio update function with annotated code]
### UI controls
[Explain how forge UI sliders and buttons connect to audio parameters]
### Rendering
[Explain how audio state maps to the visual scene. Brief — point readers
to GPU and UI lessons for rendering details.]
## Key concepts
- **Concept 1** — Brief explanation
- **Concept 2** — Brief explanation
## The audio library
This lesson adds the following to `common/audio/forge_audio.h`:
| Function | Purpose |
|---|---|
| `forge_audio_function_name()` | Brief description |
See: [common/audio/README.md](../../../common/audio/README.md)
## Where it's used
- [Math Lesson NN](../../math/NN-name/) provides the [math concept] used here
## Building
```bash
cmake -B build
cmake --build build --config Debug
# Windows
build\lessons\audio\NN-topic-name\Debug\NN-topic-name.exe
# Linux / macOS
./build/lessons/audio/NN-topic-name/NN-topic-name
```
## Exercises
1. [Exercise extending the audio concept]
2. [Exercise modifying parameters to observe different behavior]
3. [Exercise adding a new audio feature]
## Further reading
- [Relevant math lesson for the underlying math]
- [External resource — The Audio Programming Book, DAFX, Julius O. Smith, etc.]
CMakeLists.txt (root): Add add_subdirectory(lessons/audio/NN-topic-name)
under an "Audio Lessons" section (create the section if it doesn't exist
yet, placed after Physics Lessons)README.md (root): Add a row to the audio lessons table in an
"Audio Lessons (lessons/audio/)" section — follow the same format as
the existing track sections. Create the section if this is the first audio
lesson.lessons/audio/README.md: Create the track README if this is the first
lesson, or add a row to the existing lessons tablePLAN.md: Check off the audio lesson entry# Compile lesson-specific shaders (skip if lesson has no shaders/ directory)
python scripts/compile_shaders.py audio/NN-topic-name
# Build
cmake -B build
cmake --build build --config Debug
# Run
./build/lessons/audio/NN-topic-name/NN-topic-name
Use a Task agent with model: "haiku" for build commands per project
conventions.
Verify:
# Configure with capture support
cmake -B build -DFORGE_CAPTURE=ON
cmake --build build --config Debug --target NN-topic-name
# Static screenshot
python scripts/capture_lesson.py lessons/audio/NN-topic-name
Copy output to lessons/audio/NN-topic-name/assets/.
Before finalizing, launch a verification agent using the Task tool
(subagent_type: "general-purpose"). Give the agent the paths to the lesson's
README.md and main.c and ask it to audit every key topic for completeness.
For each key topic / "What you'll learn" bullet, the agent must check:
main.c actually exercise this
concept with audible and visible behavior?The lesson is incomplete until every key topic passes all four checks.
Use the /dev-markdown-lint skill to check all markdown files:
npx markdownlint-cli2 "**/*.md"
Audio lessons cover sound concepts with real-time playback and visual feedback:
Audio lessons do not cover:
Every audio lesson includes the same rendering and UI foundation so the focus stays on the audio. This baseline is not optional.
Use forge_scene.h — one forge_scene_init() call provides all of
the following. See the forge-scene-renderer skill for the full API.
| Feature | Provided by forge_scene.h | Original skill reference |
|---|---|---|
| Blinn-Phong lighting | Per-material ambient + diffuse + specular | forge-blinn-phong-materials |
| Procedural grid floor | Anti-aliased shader grid on XZ plane | forge-shader-grid |
| Shadow map | Single directional shadow map | forge-cascaded-shadow-maps |
| Sky gradient | Procedural sky background | forge-procedural-sky |
| Camera controls | WASD + mouse look with delta time | forge-camera-and-input |
| Depth buffer | Depth testing with appropriate format | forge-depth-and-3d |
| sRGB swapchain | SDR_LINEAR for correct gamma | forge-sdl-gpu-setup |
| Forge UI panel | Immediate-mode controls for audio parameters | forge-ui-rendering |
| Procedural geometry | All shapes from forge_shapes.h | forge-procedural-geometry |
| Capture support | Screenshot via forge_capture.h | dev-add-screenshot |
Sound sources and audio state should have visual representation:
Audio lessons should be practical and grounded. Digital audio has deep signal-processing roots — present the essential math clearly while keeping the focus on audible results.
forge_shapes_*() from common/shapes/forge_shapes.h.forge_pipeline_load_texture().forge-assets.toml manifests. NEVER write bespoke CMake copy commands
for fonts, textures, or models. Use forge_target_assets() in
CMakeLists.txt and list dependencies in the manifest.assets/ directories hold only screenshots and diagrams
for the README — never runtime assets.Follow the same conventions as all forge-gpu code:
ForgeAudio prefix for public types, forge_audio_ for functionsPascalCase for typedefs, lowercase_snake_case for localsUPPER_SNAKE_CASE for #define constants#define or enum everythingUse the /dev-create-diagram skill for:
Audio lessons use formulas for DSP concepts. Use inline $...$ and display
$$...$$ math notation. Display math blocks must be split across three lines
(CI enforces this).
In these cases, update existing documentation or plan for later.
audio.conf (gitignored) points to a local directory. The README
describes what types of files work best and where to find royalty-free audio.