# CLAUDE.md

Operational guide for Claude Code working in the Mawida Engine code repo. Keep
this file lean and operational. The full design rationale, architecture
write-up, roadmap, and decision log live in the companion docs repo
`fortega/mawida-docs` (`design.html`, `handoff.md`) and are deliberately kept
out of this code repo.

Author and sole credited owner of all code: Dr. Francisco R. Ortega. Do not
credit Claude or any script in source, commit messages, or docs.

## Direction (current)

Modern, code-first, 2D-first engine on wgpu. Not XNA-bound. 3D, VR, and embedded
scripting are designed to be additive, not rewrites.

- World model: a custom, lightweight ECS we build ourselves (NOT hecs, NOT
  Bevy). Generational entity ids plus type-erased component columns; systems are
  plain functions; the scheduler is a small, visible, replaceable layer a
  student can read and extend. Reason: keep the scheduler and memory model
  legible. Adds zero dependencies.
- A thin `App::run` plus `update`/`draw` facade sits on top of the ECS as a
  friendly on-ramp. It is not the defining model.
- Scripting: design the seam now, ship no runtime in v0.1. The core speaks
  data plus commands plus queries through a `ScriptHost` trait and never names a
  language. First future binding leans Lua (`mlua`); WASM stays open.
- Plugin/module registry: audio, 3D, VR, and scripting each register as a module.
- Web/WASM build of the engine itself: keep it possible (no native-only
  assumptions), but not a v0.1 target.

## Status of the code

v0.1 + v0.2 + v0.3 COMPLETE, compiling and runtime-verified as of
2026-07-07: 54 headless tests (incl. 2 doc-tests) across feature combos,
clippy zero across targets, and every milestone example verified live:
hello_quad (+_ecs), sprite_storm (10,000 sprites, ONE draw call, measured
from 514 ms/frame naive), walker, fps_text (built-in 8x8 bitmap font),
bounce, lua_fountain (hot-reloading Lua), cube3d (lit glTF cube + 2D HUD
in one frame). Features: default = runtime+audio; `lua` (mlua 0.12,
vendored 5.4) and `gltf` (1.4.1) are opt-in. 3D convention: right-handed,
+Y up, -Z forward, CCW front faces (Godot/glTF). The wgpu 29 / rodio 0.22 API
fixes are annotated in-source where each gotcha lives; per-file learning
guides are in `mawida-docs/files/`.

The ECS heart is implemented: `world.rs` (generational ids, type-erased
columns, columns_mut, resources), the App builder with the visible for-loop
scheduler and RenderQueue in `app.rs` (the Game trait on-ramp remains, both
doors share one bring-up path), `module.rs` (Module trait + AudioModule),
and `script.rs` (Command/Bundle/WorldView/ScriptHost/NullHost, no runtime,
no language named). Implementation follows the mawida-docs guides for steps
7-9 exactly; licensing provenance is recorded in
`reports/ecs-implementation-plan.html`.

## Commands

- Core logic tests only (fast, no GPU): `cargo test --no-default-features`
- Full check (pulls wgpu/winit): `cargo check`
- Run the examples: `cargo run --example hello_quad` (Game trait door) and
  `cargo run --example hello_quad_ecs` (ECS door: World + systems + modules)
- Lint / format: `cargo clippy --all-targets` and `cargo fmt`
- WASM proof (pure-logic core only): `rustup run stable cargo check --target
  wasm32-unknown-unknown --no-default-features` (NOTE: the Homebrew rustc
  cannot see rustup targets; go through rustup. The runtime layer needs
  wasm-bindgen-futures instead of pollster to run in a browser: documented
  gap, not a v0.4 target.)

## Dependency policy

Versions in Cargo.toml were verified on crates.io on 2026-06-27: wgpu 29.0.3,
winit 0.30.13, glam 0.33.1, bytemuck 1.25.0, pollster 0.4.0, image 0.25.10,
rodio 0.22.2, env_logger 0.11.11, raw-window-handle 0.6.2, thiserror 2.0.18,
log 0.4.33. The custom ECS and the scripting seam add no dependencies in v0.1.

Do not trust training-data version numbers. Before bumping wgpu or winit, check
crates.io for the current version and read that version's changelog; both make
breaking changes on a regular cadence. The MSRV in Cargo.toml (1.82) is a guess;
raise it to whatever wgpu 29 actually requires once you have compiled.

## Seams you must not break

Cheap to keep, expensive to recover. Preserve them in any change:

1. Math is always 3D (`glam` `Vec3`/`Mat4`/`Quat`). Never narrow the public API
   to `Vec2`-only. 2D is `z = 0` plus an orthographic camera.
2. Drawing goes through a `Camera`. Never hardcode screen-space pixel coords into
   a draw call or shader. 2D and 3D differ only by which `Camera` is passed.
3. Drawables are `mesh + material + transform`. Never add a privileged
   `draw_sprite(x, y)` path that bypasses the model. A sprite is "a quad mesh with
   an unlit material." In the ECS these are components an entity carries.
4. "Present" lives behind `RenderBackend::end_frame`. Never call surface present
   or swapchain logic from anywhere else. For VR this becomes "submit to the XR
   compositor," and the rest of the engine must not notice.

A fifth, weaker seam: `RenderBackend::draw` takes a camera per call, so per-eye
VR is a loop over cameras. Keep it that way; do not bake in a single global
camera.

The reasoning behind these, and the wgpu / Vulkan / OpenXR / Apple strategy, is
in the docs repo. Operationally: when VR work starts, force the Vulkan backend
and reach native handles via `wgpu-hal`; do not rewrite the renderer in raw `ash`.

## Working conventions for this repo

- Make one change at a time and verify it compiles before the next, especially in
  `wgpu_backend.rs`. Do not batch a dozen speculative API fixes.
- Back up (commit) before any destructive or wide-reaching edit.
- Prefer fixing the actual API call over deleting functionality to make it build.
- Keep comments that explain a seam or a wgpu gotcha; they are load-bearing.
- No em dashes in authored docs. Credit goes to Dr. Francisco R. Ortega.
- Design docs do not live in this repo. Put rationale, roadmaps, and decision
  records in `fortega/mawida-docs`, not here.
