diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..eeefa1d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,174 @@ +# AGENTS.md — JNR Engine + +## Important Files + +Before starting any task, always read: +- **DESIGN.md** — Game design document with vision, mechanics, and level plans +- **TODO.md** — Current roadmap and next tasks to implement + +## Project Overview + +2D side-scrolling platformer (run-and-gun) written in C11 using SDL2, SDL2_image, and SDL2_mixer. +Binary: `jnr`. Targets Linux (native), WebAssembly (Emscripten), Windows (MinGW cross-compile). + +## Build Commands + +```bash +make # Release build (Linux) → ./jnr +make run # Build + run +make debug # Debug build: -g -O0 -DDEBUG +make DEBUG=1 # Alternative debug flag +make web # WASM build → dist-web/ +make web-serve # WASM build + HTTP server on :8080 +make windows # Cross-compile → dist-win64/ +make clean # Remove all build artifacts +``` + +Compiler flags: `-Wall -Wextra -std=c11 -I include -I src` + +There are no test or lint targets. Verify changes by building with `make` and confirming zero warnings. + +### Cross-platform prerequisites + +- **WASM builds** require the Emscripten SDK. The `emsdk/` directory in the project root is + gitignored; source the environment before building: + ```bash + source ~/emsdk/emsdk_env.sh # or wherever emsdk is installed + make web + ``` +- **Windows cross-compilation** requires MinGW (`x86_64-w64-mingw32-gcc`) and vendored + SDL2 development libraries in `deps/win64/` (also gitignored). + +## Project Structure + +``` +include/ Global headers (config.h) +src/ + engine/ Engine subsystems (.c/.h pairs): physics, tilemap, entity, camera, etc. + game/ Game logic (.c/.h pairs): player, enemy, level, levelgen, editor, etc. + util/ Header-only utilities: vec2.h, darray.h + main.c Entry point, game mode switching, level transitions +assets/ + levels/ .lvl level files (plain text) + sounds/ .wav/.ogg audio + sprites/ PNG spritesheets + tiles/ Tileset PNGs +web/ Emscripten HTML shell +``` + +Engine code lives in `src/engine/`, game code in `src/game/`. Each subsystem is a `.c`/`.h` pair. +Header-only utilities use `static inline` functions. + +## Code Style + +### Formatting +- **4 spaces** for indentation (no tabs in source; Makefile uses tabs) +- **K&R brace style**: opening brace on same line +- Pointer declaration: `Type *name` (space before `*`) +- `const` for input-only pointer params: `const Tilemap *map` +- No-parameter functions use `void`: `void physics_init(void)` +- Unused parameters: `(void)param;` + +### Naming Conventions +| Kind | Convention | Example | +|------|-----------|---------| +| Functions | `snake_case`, module-prefixed | `player_update()`, `tilemap_load()` | +| Types/Structs | `PascalCase` | `Entity`, `PlayerData`, `Tilemap` | +| Enums | `PascalCase` type, `UPPER_SNAKE` values | `EntityType` / `ENT_PLAYER` | +| Macros/Constants | `UPPER_SNAKE_CASE` | `MAX_ENTITIES`, `TILE_SIZE` | +| Static (file-scope) vars | `s_` prefix | `s_gravity`, `s_renderer` | +| Global vars | `g_` prefix | `g_engine`, `g_spritesheet` | +| Local vars | Short `snake_case` | `dt`, `pos`, `em`, `tx` | +| Function pointer types | `PascalCase` + `Fn` | `EntityUpdateFn` | + +### Includes +Order within each file: +1. Own module header (`"game/player.h"`) +2. Other project headers (`"engine/physics.h"`, `"game/sprites.h"`) +3. Standard library (``, ``, ``) +4. SDL headers (``) +5. Platform-conditional (`#ifdef __EMSCRIPTEN__`) + +Paths are forward-slash, relative to `src/` or `include/`: `"engine/core.h"`, `"config.h"`. + +### Comments +- **Section headers**: `/* ═══...═══ */` box-drawing block +- **Subsections**: `/* ── Name ──────── */` light-line style +- **Inline/doc comments**: `/* ... */` (C89-style, not `//`) +- **Struct field comments**: trailing, aligned with whitespace padding + +### Header Guards +```c +#ifndef JNR_MODULE_H +#define JNR_MODULE_H +... +#endif /* JNR_MODULE_H */ +``` + +### Types +- `float` for positions, velocities, timers, physics (not `double`) +- `Vec2` (float x, y) for all 2D quantities +- `bool` from `` +- `uint16_t` for tile IDs; `uint32_t` for bitfield flags and seeds +- `SDL_Color` for colors; `SDL_Rect` for integer rectangles + +### Error Handling +- Return `bool` for success/failure +- Return `NULL` from creation functions on failure +- Errors to `stderr` via `fprintf(stderr, "...")` +- Info to `stdout` via `printf(...)` +- Warnings use `"Warning: ..."` prefix +- Early return on failure; no goto-based cleanup + +### Memory Management +- `calloc(1, sizeof(T))` for entity data (zero-initialized) +- `free(ptr); ptr = NULL;` in destroy callbacks +- `memset(ptr, 0, sizeof(*ptr))` for struct re-initialization +- Fixed-size arrays for most collections (entity pool, tile defs) +- Dynamic allocation only for tile layers (`uint16_t *`) +- `snprintf` / `strncpy` with explicit size limits for strings +- `ASSET_PATH_MAX` (256) for path buffers + +## Architecture Patterns + +### Entity System +- Fixed pool of `MAX_ENTITIES` (512) in `EntityManager` +- Dispatch tables: `update_fn[type]`, `render_fn[type]`, `destroy_fn[type]` +- `void *data` for type-specific data (cast in callbacks) +- Each entity type: `_register()` sets callbacks, `_spawn()` creates instances +- Entity registry maps string names to spawn functions for level loading + +### Module Pattern +- Public API: declared in header, module-prefixed (`camera_init`, `camera_follow`) +- Private helpers: `static` in `.c` only +- File-scope state: `static` variables with `s_` prefix +- Forward declarations to break circular includes + +### Level System +- `.lvl` files: plain-text directives + tile grid data +- `level_load()` for handcrafted levels from files +- `level_load_generated()` for procedural levels from `Tilemap` structs +- Exit zones trigger transitions; target strings: file path, `"generate"`, `"generate:station"`, or empty (victory) +- Procedural generator: segment-based, theme-driven, difficulty-scaled + +### Rendering +- Sprite batching: submit to queue via `renderer_submit()`, flush layer-by-layer +- Draw layers: BG → entities → FG → particles → HUD +- Camera transforms world coords to screen coords + +## Commit Messages +- Imperative mood, concise +- No co-authored-by or AI attribution +- Example: "Add in-game level editor with auto-discovered tile/entity palettes" + +## Key Constants (config.h) +| Constant | Value | Notes | +|----------|-------|-------| +| `SCREEN_WIDTH` | 640 | Logical resolution | +| `SCREEN_HEIGHT` | 360 | | +| `TILE_SIZE` | 16 | Pixels per tile | +| `TICK_RATE` | 60 | Fixed timestep Hz | +| `DEFAULT_GRAVITY` | 980.0f | px/s² | +| `MAX_ENTITIES` | 512 | Entity pool size | +| `MAX_ENTITY_SPAWNS` | 128 | Per-level spawn slots | +| `MAX_EXIT_ZONES` | 8 | Per-level exit zones |