Airship One Dev Skill
Use this skill for day-to-day implementation in this repository.
Purpose
Keep contributors aligned on:
- runtime architecture direction,
- npm-first developer tooling,
- release/PWA versioning flow,
- practical debugging checks before and after changes.
Current Stack and Source of Truth
- Runtime: TypeScript + Vite + Three.js.
- Deployment target: GitHub Pages.
- Architecture target: modular ECS + typed event queue + multi-rate update domains.
- Version source of truth:
package.json version.
- Theme model: runtime light/dark mode with tokenized Victorian wood/paper/velvet palette.
- Menu model: data-driven stack-based DOM overlay menus with submenu/back/close behaviors and custom menu item renderers (e.g.,
letter).
- Save model (current scaffold): browser
localStorage envelope including settings + local simulation, with JSON export/import roundtrip and persisted player pose (position, yaw, pitch).
- Ship-state model (current scaffold): authoritative geo-time fields in simulation (
shipLatitudeDeg, shipLongitudeDeg, shipAltitudeAslM, shipLocalSolarTimeHours) updated from real UTC.
- Controls model (current scaffold): dual bindings (keyboard + gamepad button/axis) with HID-safe rebind capture baseline.
- Input helper model (current scaffold): shared action-edge, pressed-state, gamepad lookup, and binding-label helpers are centralized in
src/core/input.ts.
- Module generation model: parameterized generator profiles for generic module types and exact module variants (
--interior-profile auto|none|captains-cabin).
- Module runtime registry model: one handler file per module template under
src/modules/handlers/*.ts, with src/modules/registry.ts as the single wiring point for fixed modules, insertable modules, and capability metadata (e.g., battery supply).
- Lighting model (current scaffold): UTC-driven global sun + ambient derived from authoritative ship geo-time state (lat/lon/ASL + UTC) and planet parameters.
- Lighting helper model (current scaffold): solar-state and solar-charge-effectiveness calculations are centralized in
src/render/lighting.ts.
- Electrical model (current scaffold): effective battery capacity and percent drain/charge rates scale with installed battery-supply module count across all active ladder floors.
- Battery control menu model (current scaffold): queue-driven in-place live bindings are visibility/throttle gated, and runtime display uses staged tail labeling (
A+B ... then B +tail).
- Menu module model (current scaffold): menu definition factory and row renderers are extracted to
src/ui/menu-definitions.ts and src/ui/menu-render.ts, with src/main.ts retaining menu orchestration and event wiring.
- Sky model (current scaffold): parameterized procedural sky dome (day/sunset/night gradients, sun-centered tinting, contiguous evolving cloud coverage).
- Generated version artifacts:
public/version.js (local/dev fallback and build-time overwrite),
dist/version.js (must match deployed build version).
Required Workflow
1) Local Development
./dev-prepare.sh for baseline setup/checks.
./dev-run.sh to run dev server.
./dev-test.sh for lint/typecheck/test.
./dev-build.sh for production build.
./dev-build-bump-ver.sh to bump patch version then build.
2) Release Build
- Prefer
./prod-release.sh (delegates to npm release flow).
- Build must produce:
dist/version.js with current package version,
dist/sw.js with versioned cache name,
- deployable
dist/ artifact.
3) CI/CD (Pages)
- Use
.github/workflows/build-and-deploy.yml.
- Keep build artifact path as
dist.
- Post-deploy verification remains required on live Pages URL.
Runtime Architecture Rules
- Keep simulation deterministic and decoupled from render FPS.
- Preserve planned timing domain separation:
simTick, renderTick, terrainHarvestTick, audioTick.
- Keep state transitions event/command driven.
- Keep UI as state consumer/dispatcher, not direct simulator mutator.
- Keep spherical math correctness constraints explicit in all nav work.
- Early-development fail-fast policy is strict: do not add save/data migrations, do not add fallback execution paths, and do not hide exceptions.
Floor/Module Ownership Rules
- Use explicit per-floor ownership for interior modules via level-keyed arrays (
floorModuleIdsByLevel).
- Never resolve missing floor module arrays by inheriting from another floor; missing level state is a defect and should throw.
- Keep ladder shaft alignment stable across levels by preserving a shared ladder center Z when floor layouts are rebuilt.
- Compute movement/collision bounds from actual rendered placement extents, not assumptions tied to only one active floor.
- When selecting active level fallback, compare player eye Y against level standing-eye heights, not deck base Y.
- Ladder climb min-Y clamps must be level-relative for lowest/negative levels to avoid descend snap-back.
Module Type Extension Rules
- Add new module templates by creating a dedicated handler file in
src/modules/handlers/ and exporting it via src/modules/handlers/index.ts.
- Keep module capability flags (e.g., battery supply) in handler metadata, not hardcoded ID-prefix checks in runtime logic.
- Route chain construction and insertable-choice generation through
src/modules/registry.ts only.
- Keep fixed module rules (
cockpit front, cargo rear) enforced by registry-level logic.
Rendering and UI Guardrails
- Preserve 320x320 logical rendering concept.
- Keep menu/dialog UI as accessible DOM overlays.
- Use pixel-style scale tokens; avoid random per-component hardcoded styling.
- Interaction-triggered menu close may request pointer recapture, but explicit user
Escape to free cursor must always cancel pending recapture.
Known Early Pitfall: Growing Canvas/Square in Dev
If visual surface appears to grow continuously:
- Check for
ResizeObserver feedback loops where observed size is immediately rewritten.
- Avoid style updates that change the observed container dimensions each callback.
- Prefer stable wrapper sizing and only update renderer/canvas dimensions from external layout changes.
- Add temporary logging around resize callback dimensions to verify convergence.
Known Early Pitfall: Texture Update Warning on First Frames
If you see THREE.WebGLRenderer: Texture marked for update but no image data found:
- Ensure tile textures are preloaded before creating module meshes/materials.
- Avoid cloning repeat-variant textures before the source image is loaded.
- Centralize texture configuration (wrap, color space, anisotropy) for both preload and fallback load paths.
Known Early Pitfall: Ladder Floor Teleport/Snap Bugs
If floor add/remove or descend behavior causes apparent teleports:
- Verify level-anchor fallback uses standing-eye height (
level * deckHeight + eyeHeight).
- Verify climb volume floor clamp uses level-relative eye-height when no lower floor exists.
- Avoid index-based remapping assumptions across multi-floor rebuilds unless index domain is level-scoped and stable.
Known Early Pitfall: Pointer Lock Races During Menu Close
If console logs SecurityError after click/close transitions:
- Expect pointer-lock request races during unlock and handle
requestPointerLock() promise rejection for known unlock races.
- Keep a single helper for pointer-lock requests so
SecurityError handling is consistent.
- Ensure
Escape intent cancels pending recapture semantics.
Known Early Pitfall: Procedural Clouds Look “Vector-Like”
If sky clouds look like hard cutout shapes:
- Add domain warping before primary cloud density sampling.
- Use edge erosion/detail noise instead of a single hard threshold.
- Keep sky dome tessellation high enough for smooth directional interpolation with high-frequency cloud fields.
Pre-Commit / Pre-Handoff Checklist
- Run
./dev-test.sh and ./dev-build.sh.
- Confirm
dist/version.js matches package.json version.
- Confirm
dist/sw.js regenerated in build.
- Update
ROADMAP.md status and any parity notes touched by the change.
- Keep
.github/copilot-instructions.md current if project reality changed.
Post-Deploy Checklist (GitHub Pages)
- Validate first-load app shell and no critical console errors.
- Validate manifest installability.
- Validate offline refresh after first online visit.
- Validate update path by version bump + redeploy (service worker update lifecycle).
- Validate repo-subpath asset/deep-link behavior on Pages.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: airship-one-dev3description: Airship One implementation playbook for runtime architecture, npm-first tooling, release/PWA flow, and debugging checks. Use when this capability is needed.4---56# Airship One Dev Skill78Use this skill for day-to-day implementation in this repository.910## Purpose1112Keep contributors aligned on:13- runtime architecture direction,14- npm-first developer tooling,15- release/PWA versioning flow,16- practical debugging checks before and after changes.1718## Current Stack and Source of Truth1920- Runtime: TypeScript + Vite + Three.js.21- Deployment target: GitHub Pages.22- Architecture target: modular ECS + typed event queue + multi-rate update domains.23- Version source of truth: `package.json` `version`.24- Theme model: runtime light/dark mode with tokenized Victorian wood/paper/velvet palette.25- Menu model: data-driven stack-based DOM overlay menus with submenu/back/close behaviors and custom menu item renderers (e.g., `letter`).26- Save model (current scaffold): browser `localStorage` envelope including settings + local simulation, with JSON export/import roundtrip and persisted player pose (`position`, `yaw`, `pitch`).27- Ship-state model (current scaffold): authoritative geo-time fields in simulation (`shipLatitudeDeg`, `shipLongitudeDeg`, `shipAltitudeAslM`, `shipLocalSolarTimeHours`) updated from real UTC.28- Controls model (current scaffold): dual bindings (keyboard + gamepad button/axis) with HID-safe rebind capture baseline.29- Input helper model (current scaffold): shared action-edge, pressed-state, gamepad lookup, and binding-label helpers are centralized in `src/core/input.ts`.30- Module generation model: parameterized generator profiles for generic module types and exact module variants (`--interior-profile auto|none|captains-cabin`).31- Module runtime registry model: one handler file per module template under `src/modules/handlers/*.ts`, with `src/modules/registry.ts` as the single wiring point for fixed modules, insertable modules, and capability metadata (e.g., battery supply).32- Lighting model (current scaffold): UTC-driven global sun + ambient derived from authoritative ship geo-time state (lat/lon/ASL + UTC) and planet parameters.33- Lighting helper model (current scaffold): solar-state and solar-charge-effectiveness calculations are centralized in `src/render/lighting.ts`.34- Electrical model (current scaffold): effective battery capacity and percent drain/charge rates scale with installed battery-supply module count across all active ladder floors.35- Battery control menu model (current scaffold): queue-driven in-place live bindings are visibility/throttle gated, and runtime display uses staged tail labeling (`A+B ... then B +tail`).36- Menu module model (current scaffold): menu definition factory and row renderers are extracted to `src/ui/menu-definitions.ts` and `src/ui/menu-render.ts`, with `src/main.ts` retaining menu orchestration and event wiring.37- Sky model (current scaffold): parameterized procedural sky dome (day/sunset/night gradients, sun-centered tinting, contiguous evolving cloud coverage).38- Generated version artifacts:39 - `public/version.js` (local/dev fallback and build-time overwrite),40 - `dist/version.js` (must match deployed build version).4142## Required Workflow4344### 1) Local Development45- `./dev-prepare.sh` for baseline setup/checks.46- `./dev-run.sh` to run dev server.47- `./dev-test.sh` for lint/typecheck/test.48- `./dev-build.sh` for production build.49- `./dev-build-bump-ver.sh` to bump patch version then build.5051### 2) Release Build52- Prefer `./prod-release.sh` (delegates to npm release flow).53- Build must produce:54 - `dist/version.js` with current package version,55 - `dist/sw.js` with versioned cache name,56 - deployable `dist/` artifact.5758### 3) CI/CD (Pages)59- Use `.github/workflows/build-and-deploy.yml`.60- Keep build artifact path as `dist`.61- Post-deploy verification remains required on live Pages URL.6263## Runtime Architecture Rules6465- Keep simulation deterministic and decoupled from render FPS.66- Preserve planned timing domain separation:67 - `simTick`, `renderTick`, `terrainHarvestTick`, `audioTick`.68- Keep state transitions event/command driven.69- Keep UI as state consumer/dispatcher, not direct simulator mutator.70- Keep spherical math correctness constraints explicit in all nav work.71- Early-development fail-fast policy is strict: do not add save/data migrations, do not add fallback execution paths, and do not hide exceptions.7273## Floor/Module Ownership Rules7475- Use explicit per-floor ownership for interior modules via level-keyed arrays (`floorModuleIdsByLevel`).76- Never resolve missing floor module arrays by inheriting from another floor; missing level state is a defect and should throw.77- Keep ladder shaft alignment stable across levels by preserving a shared ladder center Z when floor layouts are rebuilt.78- Compute movement/collision bounds from actual rendered placement extents, not assumptions tied to only one active floor.79- When selecting active level fallback, compare player eye Y against level standing-eye heights, not deck base Y.80- Ladder climb min-Y clamps must be level-relative for lowest/negative levels to avoid descend snap-back.8182## Module Type Extension Rules8384- Add new module templates by creating a dedicated handler file in `src/modules/handlers/` and exporting it via `src/modules/handlers/index.ts`.85- Keep module capability flags (e.g., battery supply) in handler metadata, not hardcoded ID-prefix checks in runtime logic.86- Route chain construction and insertable-choice generation through `src/modules/registry.ts` only.87- Keep fixed module rules (`cockpit` front, `cargo` rear) enforced by registry-level logic.8889## Rendering and UI Guardrails9091- Preserve 320x320 logical rendering concept.92- Keep menu/dialog UI as accessible DOM overlays.93- Use pixel-style scale tokens; avoid random per-component hardcoded styling.94- Interaction-triggered menu close may request pointer recapture, but explicit user `Escape` to free cursor must always cancel pending recapture.9596### Known Early Pitfall: Growing Canvas/Square in Dev9798If visual surface appears to grow continuously:99- Check for `ResizeObserver` feedback loops where observed size is immediately rewritten.100- Avoid style updates that change the observed container dimensions each callback.101- Prefer stable wrapper sizing and only update renderer/canvas dimensions from external layout changes.102- Add temporary logging around resize callback dimensions to verify convergence.103104### Known Early Pitfall: Texture Update Warning on First Frames105106If you see `THREE.WebGLRenderer: Texture marked for update but no image data found`:107- Ensure tile textures are preloaded before creating module meshes/materials.108- Avoid cloning repeat-variant textures before the source image is loaded.109- Centralize texture configuration (wrap, color space, anisotropy) for both preload and fallback load paths.110111### Known Early Pitfall: Ladder Floor Teleport/Snap Bugs112113If floor add/remove or descend behavior causes apparent teleports:114- Verify level-anchor fallback uses standing-eye height (`level * deckHeight + eyeHeight`).115- Verify climb volume floor clamp uses level-relative eye-height when no lower floor exists.116- Avoid index-based remapping assumptions across multi-floor rebuilds unless index domain is level-scoped and stable.117118### Known Early Pitfall: Pointer Lock Races During Menu Close119120If console logs `SecurityError` after click/close transitions:121- Expect pointer-lock request races during unlock and handle `requestPointerLock()` promise rejection for known unlock races.122- Keep a single helper for pointer-lock requests so `SecurityError` handling is consistent.123- Ensure `Escape` intent cancels pending recapture semantics.124125### Known Early Pitfall: Procedural Clouds Look “Vector-Like”126127If sky clouds look like hard cutout shapes:128- Add domain warping before primary cloud density sampling.129- Use edge erosion/detail noise instead of a single hard threshold.130- Keep sky dome tessellation high enough for smooth directional interpolation with high-frequency cloud fields.131132## Pre-Commit / Pre-Handoff Checklist133134- Run `./dev-test.sh` and `./dev-build.sh`.135- Confirm `dist/version.js` matches `package.json` version.136- Confirm `dist/sw.js` regenerated in build.137- Update `ROADMAP.md` status and any parity notes touched by the change.138- Keep `.github/copilot-instructions.md` current if project reality changed.139140## Post-Deploy Checklist (GitHub Pages)141142- Validate first-load app shell and no critical console errors.143- Validate manifest installability.144- Validate offline refresh after first online visit.145- Validate update path by version bump + redeploy (service worker update lifecycle).146- Validate repo-subpath asset/deep-link behavior on Pages.147148---149> Converted and distributed by [TomeVault](https://tomevault.io/claim/timelessp) — claim your Tome and manage your conversions.150<!-- tomevault:4.0:skill_md:2026-04-13 -->