Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c5db111
fix(ci): repair benchmarks workflow, enable dotnet coverage, expand C…
aram-devdocs Jul 3, 2026
75af57a
fix(hooks): scan MultiEdit payloads, harden command guard, add fixtures
aram-devdocs Jul 3, 2026
7f034c7
fix(bench): register pool and physics bench harnesses, refresh bench …
aram-devdocs Jul 3, 2026
9b3c005
fix(clippy): remove unused imports surfaced by the full gate
aram-devdocs Jul 3, 2026
1840cbd
fix(hooks): scope the removal guard to system roots only
aram-devdocs Jul 3, 2026
c809985
feat(verify): canonical verification gate shared by hooks and CI
aram-devdocs Jul 3, 2026
6d7f747
test(native): add a headless opt-out for the native smoke tests
aram-devdocs Jul 3, 2026
b8914a6
fix(deny): triage newly-surfaced dependency advisories (#704)
aram-devdocs Jul 3, 2026
72f530f
ci: secret scanning, PR-size gate, and faster PR feedback
aram-devdocs Jul 3, 2026
167e069
chore(repo): purge dead solution file, stale audit specs, and .gitign…
aram-devdocs Jul 3, 2026
9e3e54f
docs: correct README project map and add CONTRIBUTING gate/MSRV/owner…
aram-devdocs Jul 3, 2026
6b7c8a7
docs: list all 10 SDKs and refresh the docs structure map
aram-devdocs Jul 3, 2026
e433d2c
chore(version): align stale SDK version pins to 0.0.841
aram-devdocs Jul 3, 2026
6aba762
docs(agents): fix FFI regen instruction and dispatch-table drift
aram-devdocs Jul 3, 2026
c812f82
docs(skills): de-stale SDK/layer maps and fix broken references
aram-devdocs Jul 3, 2026
80fb32b
refactor(scripts): de-duplicate validators, fix portability, document…
aram-devdocs Jul 3, 2026
2aefd7b
docs(governance): add security policy, versioning, standards, and ADRs
aram-devdocs Jul 3, 2026
1c5d118
fix(arch): classify jni/ and ui/ in the layer linter
aram-devdocs Jul 3, 2026
a4b7d77
docs(arch): unify nested AGENTS.md layer labels to the canonical model
aram-devdocs Jul 3, 2026
eea7a59
docs(rules): add module rules for ui, jni, networking, wasm, and comp…
aram-devdocs Jul 3, 2026
4afc8df
feat(agents): generate .cursor/rules from the canonical .agents/rules
aram-devdocs Jul 3, 2026
d472a9d
fix(packaging): pack build/GoudEngine.targets into the NuGet package …
aram-devdocs Jul 3, 2026
a02d22f
feat(render): headless benchmarking support in NullBackend
aram-devdocs Jul 3, 2026
a5dd119
feat(bench): renderer frame + engine-tick benches with a ratio-normal…
aram-devdocs Jul 3, 2026
334239d
chore(bench): capture pre-optimization baseline measurements
aram-devdocs Jul 3, 2026
147fbbf
perf: use FxHashMap for hot renderer3d-state and ECS World maps
aram-devdocs Jul 3, 2026
e5f9900
fix(ffi): free component storage on despawn and reject stale-generati…
aram-devdocs Jul 3, 2026
3a0ec08
feat(hooks): add lifecycle hooks for challenge, quality, session, and…
aram-devdocs Jul 3, 2026
b44b9f2
feat(rules): add discovery-first, challenge, compaction, and doc-stan…
aram-devdocs Jul 3, 2026
bf5e68c
feat(skills): add skill validator, authoring standard, and four new s…
aram-devdocs Jul 3, 2026
598ab12
feat(verify): gate on the skill validator and hook test harness
aram-devdocs Jul 3, 2026
dab2ec3
docs(governance): add engineering constitution and enforcement map
aram-devdocs Jul 3, 2026
b0545a6
feat(render): env-selectable software fallback adapter
aram-devdocs Jul 3, 2026
313a434
feat(infra): dockerized headless test environment and GPU CI lane
aram-devdocs Jul 3, 2026
4e29ad6
docs(perf): add the optimization roadmap for follow-up work
aram-devdocs Jul 3, 2026
7628f16
fix(render): move the force-fallback test module to end of file
aram-devdocs Jul 3, 2026
d2fbf1c
ci: allowlist hook fixtures for gitleaks and GitGuardian
aram-devdocs Jul 3, 2026
ed34579
ci: sync cargo-audit ignore list with deny.toml (#704)
aram-devdocs Jul 3, 2026
f9aa00b
chore(deps): npm audit fix for the TypeScript SDK
aram-devdocs Jul 3, 2026
c04d2f9
fix(ffi): purge the FFI component storage on despawn (correct storage…
aram-devdocs Jul 3, 2026
1281fb1
Merge remote-tracking branch 'origin/main' into overhaul/gate-cleanup…
aram-devdocs Jul 3, 2026
42562f1
chore(deps): ignore new cgmath advisories (#704)
aram-devdocs Jul 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .agents/rules/challenge-protocol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
description: How reviewers, implementers, and auditors challenge work
alwaysApply: true
---

# Challenge Protocol

Every agent argues from evidence. Authority — being the lead, being first, being senior — settles nothing.

## Reviewers

- A reviewer MUST raise at least one concrete concern anchored to `file:line`, OR state explicitly why no concern exists after a real pass ("checked X, Y, Z; no issue because ...").
- A reviewer MUST end with an explicit verdict. Mirror what the `review-verdict-validator` hook expects (`.claude/hooks/review-verdict-validator.sh`): the last assistant message MUST contain one of `APPROVED`, `CHANGES REQUESTED`, or (for auditors) `REJECTED`. A review with no verdict is incomplete and the hook blocks it.
- "Looks good" without evidence is not a review.

## Implementers

- An implementer MUST declare the assumptions they made, the exact commands they ran (with pass/fail), and the files they changed.
- Unverified assumptions MUST be labeled as such, not presented as fact.

## Security Auditor

- The `security-auditor` MUST walk the unsafe/FFI/pointer checklist: `#[no_mangle] extern "C"`, `#[repr(C)]`, null checks on every pointer parameter, a `// SAFETY:` comment on every `unsafe` block, and documented allocate/free ownership.
- Each checklist item MUST be marked pass or fail with `file:line`.

## Disagreement

- Disagreement is resolved by evidence — code, validator output, a reproducing case — never by deferring to a prior agent's authority or seniority.
- "The lead already decided" is not a rebuttal. Cite the code or concede.
25 changes: 25 additions & 0 deletions .agents/rules/compaction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
description: Session memory discipline around context compaction
alwaysApply: true
---

# Compaction Discipline

Conversational context is volatile. Compaction and resume erase working memory, so durable state lives in `.claude/memory/SESSION.md`, not in the transcript.

## Before Compaction

- You MUST bring `.claude/memory/SESSION.md` current before the context is compacted: the task in flight, decisions made, commands run, files touched, and the next concrete step.
- The log is append-only. You MUST NOT rewrite or delete prior entries — add a new dated entry instead.
- Anything not written to `SESSION.md` is assumed lost.

## After Resume

- On resume, you MUST re-read `.claude/memory/SESSION.md` AND run `git status` before taking any action.
- You MUST NOT resume from conversational memory alone — treat the transcript as untrustworthy after a compaction boundary.
- Reconcile the log against `git status`: if the working tree disagrees with what the log claims, trust the tree and correct the log.

## Keeping the Log Honest

- Record enough that a cold agent could continue with only `SESSION.md` and `git status`.
- Never fabricate progress. If a step's outcome is unknown after resume, re-verify it before marking it done.
25 changes: 25 additions & 0 deletions .agents/rules/component-ops.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
globs:
- "**/component_ops/**"
- "**/context_registry/**"
alwaysApply: false
---

# Component Ops and Context Registry Patterns

`component_ops/` and `context_registry/` are top-level Layer 4 (Engine) modules — reached as `crate::component_ops` and `crate::context_registry`, not under `core/`. They MAY import from lower layers (`core/`, `ecs/`) and each other, and are consumed by Layer 5 (`ffi/`, `wasm/`, `jni/`). They MUST NOT import from `ffi/` or `sdk/`.

## Context Registry

- A `GoudContext` is one isolated engine instance: it owns its own ECS `World`, generation counter, and (in debug) thread-ownership tracking. Multiple contexts coexist (game instances, editor viewports, test isolation).
- `GoudContextId` is a generational handle encoding slot index + generation. Destroying a context increments the slot's generation, so a stale ID fails validation instead of aliasing a reused context. Never construct or compare raw IDs.
- The global registry is a singleton behind `Mutex`, reached via `get_context_registry()` (backed by `OnceLock`). Lifecycle: `get_context_registry().lock().create()` -> operate with the `GoudContextId` as the first parameter of every op -> `registry.destroy(id)` to free the slot.
- Locking: the registry Mutex protects create/destroy and slot lookup. Individual contexts are NOT `Send`/`Sync` — use a context only from the thread that created it. `GoudContextHandle` wraps `Arc<RwLock<...>>` for shared access within that thread. Hold the registry lock as briefly as possible and never call back into the registry while holding it.

## Component Ops

- This module implements type-erased component operations (`component_register_type_impl`, `component_add_impl`, `remove`, `has`, `get`, `get_mut`, plus batch variants in `batch_ops.rs`). Both the FFI `#[no_mangle]` wrappers and the Rust SDK call these `_impl` functions, so logic lives here once.
- Components cross the boundary as raw byte pointers plus a `type_id_hash` and `size`/`align` metadata, because the FFI layer does not know concrete Rust types at compile time. Storage is `RawComponentStorage`, a sparse-set-like byte store (`sparse` index -> `dense` array of entities + `data` pointers).
- Storage state lives in module-level statics guarded by `Mutex`: `CONTEXT_COMPONENT_STORAGE` (per-context storage maps) and `COMPONENT_TYPE_REGISTRY` (global type info), both `Mutex<Option<HashMap<...>>>` accessed through their guard helpers. Take the lock, operate, drop it — do not leak a `MutexGuard` across an FFI return.
- `RawComponentStorage` carries `unsafe impl Send + Sync`; that soundness relies entirely on the registry/storage Mutexes serializing access. Do not add a code path that touches the raw pointers without holding the lock.
- All `_impl` functions in `single_ops.rs`/`batch_ops.rs` are `unsafe`. Callers MUST pass pointers to valid data whose size/alignment match the registered type, and keep that memory valid for the call's duration. Every `unsafe` block needs a `// SAFETY:` comment.
4 changes: 2 additions & 2 deletions .agents/rules/dependency-hierarchy.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ GoudEngine follows a strict 5-layer architecture. Dependencies flow DOWN only.
```
Layer 1 (Foundation): core/
Layer 2 (Libs): libs/
Layer 3 (Services): ecs/, assets/
Layer 3 (Services): ecs/, assets/, ui/
Layer 4 (Engine): sdk/, rendering/, component_ops/, context_registry/
Layer 5 (FFI): ffi/, wasm/
Layer 5 (FFI): ffi/, wasm/, jni/
```

SDKs (`sdks/`) and Apps (`examples/`) sit outside `goud_engine/src/` and connect via FFI only.
Expand Down
26 changes: 26 additions & 0 deletions .agents/rules/discovery-first.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
description: Verify current state before any claim or edit
alwaysApply: true
---

# Discovery First

Claims about this codebase MUST be grounded in what the code actually says right now, not in what any document, memory file, or `AGENTS.md` listing asserts.

## Before You Claim or Edit

- You MUST `grep`/`read` the relevant files before stating how something works or before changing it.
- You MUST cite `file:line` evidence for any non-trivial claim about behavior, structure, or wiring.
- You MUST NOT trust a doc's file list, an `AGENTS.md` table, an auto-memory note, or a prior agent's summary over the actual source. These drift; the source does not.
- You MUST re-check state that a doc describes as fixed — feature flags, layer membership, exported symbols, and default features change without the doc following.

## When Doc and Code Disagree

- The code and the validators (`cargo run -p lint-layers`, `codegen/validate_coverage.py`, `check-agents-md.sh`, `cargo clippy -- -D warnings`) are the source of truth. The doc is not.
- When a doc contradicts what the code or a validator reports, the code/validator wins.
- You MUST fix the stale doc in the SAME change that surfaced the contradiction. Do not defer it, do not open a follow-up, do not leave a `TODO`.

## Evidence Format

- Quote the exact `path:line` you relied on when the precise text is load-bearing (a signature, a guard, a flag).
- Prefer a fresh `grep` over recalling a result from earlier in the session — the tree may have moved under you.
37 changes: 37 additions & 0 deletions .agents/rules/documentation-standards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
globs:
- "**/*.md"
- "**/*.rs"
- "**/*.cs"
- "**/*.py"
- "**/*.ts"
---

# Documentation Standards

Comments and docs carry intent. They MUST NOT carry process noise, and they MUST NOT narrate the diff.

## Comment-Slop Blocklist

The following are banned in comments and doc text:

- Attribution lines ("added by ...", "per Aram", agent names).
- Dates and timestamps embedded in comments.
- Phase or step labels ("Phase 2:", "Step 3 of refactor").
- Change-narration ("changed this to ...", "was previously ...", "now uses ...").
- AI filler ("Note that", "It's worth mentioning", "As we can see", "Certainly").
- Commented-out dead code. Delete it — git preserves history.

## Comments Explain WHY, Not WHAT

- A comment MUST explain intent, a non-obvious constraint, or a hazard — not restate what the line plainly does.
- If the code needs a comment to be readable, prefer renaming or restructuring first.

## Suppression Pragmas Need a Reason

- No suppression pragma without an inline justification: `#[allow(..)]` (Rust), `# noqa` (Python), `eslint-disable` (TS) MUST each carry a short reason on the same line explaining why the lint is wrong here.
- An unexplained suppression is treated as a defect.

## Enforcement

- `check-agents-md.sh` enforces the `AGENTS.md` line cap and bans stale patterns across the local `AGENTS.md` files. Keep those files under the cap and free of the banned patterns, or the check fails.
31 changes: 31 additions & 0 deletions .agents/rules/jni-mobile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
globs:
- "goud_engine/src/jni/**"
- "sdks/kotlin/**"
- "examples/android/**"
alwaysApply: false
---

# JNI and Mobile Patterns

The JNI bridge (`goud_engine/src/jni/`) is a Layer 5 (FFI) module. It is the JVM-facing boundary that backs the Kotlin SDK (`sdks/kotlin/`) and the Android examples (`examples/android/`). Like all Layer 5 code, it MAY depend on any lower layer but nothing depends on it inside the engine.

## Generated Code

- `generated.rs` and `generated.g.rs` are codegen output produced by `codegen/gen_jni.py`. They MUST NOT be hand-edited. To change an export, update the Rust engine + FFI + schema, then rerun `./codegen.sh`.
- The generated Kotlin under `sdks/kotlin/src/main/kotlin/com/goudengine/` (for example `types/*.kt`) is likewise generated. Never hand-edit it.
- `crate::jni::` refers to this bridge module; the external `jni` crate is reached as `jni::` inside generated code. Keep the module name `jni` so both resolve correctly (see `mod.rs`).

## Boundary Safety

- Every JNI entry point MUST catch panics at the boundary. Wrap the body in `catch_jni_panic` (which uses `catch_unwind(AssertUnwindSafe(...))`); a panic unwinding into the JVM is undefined behavior.
- Convert Rust errors into thrown Java exceptions using the `throw_*` helpers (`throw_null_pointer` -> `NullPointerException`, `throw_illegal_argument` -> `IllegalArgumentException`, `throw_illegal_state`/`throw_engine_error` -> `IllegalStateException`, `throw_panic` for caught panics). Do not return sentinel values where an exception is expected.
- Call `prepare_call` at the start of a bridged function to clear any pending exception and reset the last-error slot before touching engine state.
- Null-check every `jobject`/pointer parameter before use and throw rather than dereferencing. Helpers such as `throw_null_pointer` return `JniCallResult` so callers can early-return.
- The bridge reuses the C FFI's thread-local last-error channel (`goud_last_error_code`/`goud_last_error_message`). Query it through the helpers, never by reimplementing the size-discovery protocol.

## Kotlin SDK and Android

- The Kotlin SDK is a thin wrapper: it loads the native library and calls JNI functions. It MUST NOT implement game logic, math, or rendering — push that into Rust and expose it via FFI.
- Keep feature parity with the other SDKs. After JNI changes, rerun `./codegen.sh` and run the Kotlin tests under `sdks/kotlin/src/test/`.
- Android examples (`examples/android/`, for example `flappy_bird`) depend on the Kotlin SDK only, never on engine internals. Keep them in sync when the SDK API changes.
24 changes: 24 additions & 0 deletions .agents/rules/networking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
globs:
- "**/networking/**"
alwaysApply: false
---

# Networking Patterns

The networking module (`goud_engine/src/libs/networking/`) is Layer 2 (Libs). It holds transport-agnostic netcode built on top of the provider transport boundary. It MAY import from `core/` (and its own layer) only.

## Provider Transport Boundary

- The transport is abstracted behind the `NetworkProvider` trait, defined canonically in `core/providers/network.rs` and re-exported via `crate::libs::providers::network`. Concrete transports (UDP, TCP, WebSocket, WebRTC, P2P mesh, null, simulation) live in `libs/providers/impls/`.
- `NetworkProvider` is object-safe and stored as a boxed trait object. It exposes connection lifecycle (`host`, `connect`, `disconnect`, `disconnect_all`), `send`/`broadcast` over typed `Channel`s, `drain_events`, and stats — nothing above it should name a concrete provider.
- The transport moves **raw bytes only**. It never inspects, frames, or serializes payloads; serialization is the caller's responsibility. Keep it that way.
- `drain_events` returns an owned `Vec<NetworkEvent>` and MUST be called once per frame. It clears the internal buffer so the caller can process events without holding a borrow on the provider.
- `ConnectionId` values are meaningful only within the provider instance that issued them. Never cache a connection ID and use it against a different provider or engine context. The same applies to stats — resolve the active provider handle first.

## Higher-Level Netcode

- `rpc.rs` (`RpcFramework`) sits above the transport. It does **not** own a provider: `call()` and `process_incoming()` produce `OutgoingRpcMessage` values that the caller sends over Channel 0 (reliable-ordered), and inbound bytes are fed back in. Keep this transport-independence.
- RPC wire format is fixed: `[2 bytes rpc_id][8 bytes call_id][1 byte msg_type][payload]`, where `msg_type` is 0 = call, 1 = success response, 2 = error response. RPCs are registered with a direction (`ServerToClient`, `ClientToServer`, `Bidirectional`).
- `rollback.rs` implements GGPO-style rollback: local input prediction, ring-buffer state snapshots, mismatch-triggered resimulation, and hash-based desync detection. Game state participates by implementing the `GameState` trait (`advance` for one deterministic tick, `state_hash` for desync checks).
- Rollback correctness depends on determinism: `advance` must be pure over its inputs, and `state_hash` must be stable across peers. Do not introduce nondeterminism (unordered iteration, wall-clock reads, floating-point drift) into either.
5 changes: 5 additions & 0 deletions .agents/rules/orchestrator-protocol.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
description: Orchestrator workflow and agent dispatch protocol
alwaysApply: true
---

# Orchestrator Protocol

Use the smallest workflow that still protects quality.
Expand Down
34 changes: 34 additions & 0 deletions .agents/rules/ui-patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
globs:
- "goud_engine/src/ui/**"
alwaysApply: false
---

# UI Subsystem Patterns

The UI system (`goud_engine/src/ui/`) is a Layer 3 (Services) module. It MAY import from `core/` and `ecs/`, and is consumed by higher layers (`sdk/`, `rendering/`, `ffi/`, `wasm/`). It MUST NOT import from any Layer 4 or Layer 5 module.

## Node Tree

- The UI tree is standalone and separate from the ECS `World` — do not conflate `UiNode` with an ECS entity.
- Nodes are identified by generational `UiNodeId` values (index + generation). Never store or compare raw indices; a stale ID must fail validation, not alias a reused slot.
- `UiNodeAllocator` hands out and recycles node IDs. `UiManager` owns the full tree and is the only entry point for creating, reparenting, or destroying nodes.
- Each `UiNode` carries an optional `UiComponent`, its parent/child links, layout properties (anchor, position mode, size, margin, padding), computed rect, visibility, and input/focus flags.

## Widgets

- `UiComponent` is a closed enum: `Panel`, `Button`, `Label`, `Image`, `Slider`. Add new widget kinds as variants here, not as external types.
- Widget structs (`UiButton`, `UiLabel`, `UiImage`, `UiSlider`) hold intrinsic settings/state only — plain data, no side-effecting methods.
- The FFI/SDK widget-kind integer codes are mapped in `component_from_widget_kind` (`mod.rs`). Keep that mapping in sync when adding a variant, and update every SDK.

## Layout

- Layout primitives live in `layout.rs` (`PositionMode`, `UiAnchor`, `UiEdges`, `UiLayout`, `UiFlexLayout`, `UiJustify`, `UiAlign`, `UiFlexDirection`).
- `PositionMode::Relative` (default) means the layout system computes the rect; `Absolute` means the position is set explicitly. Read the computed rect, set the local properties.
- Layout, input hit-testing, and render-command emission are split across `manager/layout.rs`, `manager/input.rs`, and `manager/render.rs`. Keep each concern in its own module.

## Events and Theming

- `UiManager` produces `UiEvent` values (`HoverEnter`, `HoverLeave`, `FocusChanged`, `Click`). `map_ui_event` packs them into `PackedUiEvent` (node IDs packed as `index | generation << 32`) for FFI/WASM consumers.
- Visual styling flows through `theme.rs` (`UiTheme`, `UiVisualStyle`, `UiStyleOverrides`) and is resolved per node via `resolve_widget_visual` against the node's `UiInteractionState`. Do not hardcode colors or fonts in nodes; use the theme plus optional per-node overrides.
- Rendering is data-driven: the manager emits `UiRenderCommand` values (`UiQuadCommand`, `UiTexturedQuadCommand`, `UiTextCommand`) rather than calling the renderer directly.
32 changes: 32 additions & 0 deletions .agents/rules/wasm-web.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
globs:
- "goud_engine/src/wasm/**"
- "sdks/typescript/**"
alwaysApply: false
---

# WASM and Web Target Patterns

The WASM module (`goud_engine/src/wasm/`) is a Layer 5 (FFI) module — the browser boundary, parallel to the C FFI and JNI bridges. It exposes the engine to JavaScript via `wasm-bindgen` and backs the browser build of the TypeScript SDK (`sdks/typescript/`).

## Target and Backend

- Target is `wasm32-unknown-unknown` only. Code here MUST compile without native-only dependencies; guard anything native behind `cfg` and keep the browser path self-contained.
- Rendering uses the wgpu backend attached to an HTML canvas — never the legacy OpenGL path. The WASM sprite batcher (`sprite_renderer.rs`) is separate from the native renderer; do not assume shared code.
- `WasmGame` is the main handle exposed to JS. Construct headless via `WasmGame::new(w, h, title)` or with rendering via `create_with_canvas(...)`. Input is push-based: JS calls `press_key()`/`release_key()`.

## Networking and Debugger Attach

- Browser networking (`network.rs`) is WebSocket client only; hosting/server behavior is intentionally unsupported in the browser. Addresses are normalized to `ws://`/`wss://`.
- The WASM debugger is attached over a WebSocket relay, not a local IPC socket. Call `initDebugger(routeLabel)` once after construction (it registers the context with `publish_local_attach: false`), then the relay forwards IPC verbs through `dispatchDebuggerRequest(json)`, which returns a JSON response.

## TypeScript SDK

- The SDK has two targets: Node.js via napi-rs (`src/node/`) and browser via WASM (`src/web/`). It is a thin wrapper — no game logic, math, or rendering in TS.
- f64 vs f32: napi-rs uses JS `f64`, the engine uses `f32`. The Node path converts at the boundary; the WASM path uses `f32` directly. Do not assume f64 precision carries through.
- `.g.rs` and `.g.ts` files are codegen output and MUST NOT be hand-edited. `index.js`/`index.d.ts` are auto-built napi loaders and are gitignored — never commit them.

## Build Path

- Browser build: `npm run build:web`, which runs `wasm-pack build ../../goud_engine --target web --out-dir ../sdks/typescript/wasm --features web --no-default-features` then compiles the web TS.
- Native build: `npm run build:native` (napi-rs). After any FFI/WASM export change, rerun `./codegen.sh` and the SDK smoke tests, and keep parity with the other SDKs.
Loading
Loading