Skip to content
RubindaiPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Re:Color Studio (TypeScript)

This project is a strict-TypeScript game/editor prototype focused on extensibility:

  • multi-level catalogs
  • pluggable enemy and player behaviors
  • typed obstacle pipeline
  • physics adapter boundary

Runtime Baseline (LTS)

  • Node.js: 24.13.1 (latest LTS baseline for this repo)
  • npm: 11.8.0 (bundled with Node 24.13.1)
  • Version pins are enforced via:
    • .nvmrc
    • .npmrc (engine-strict=true)
    • package.json (engines + packageManager)
    • .github/workflows/ci.yml

Quick Start

  1. Use the pinned runtime:
nvm install
nvm use
node -v
npm -v
  1. Install dependencies:
npm ci
  1. Validate quality gates:
npm run check
  1. Start the local server:
npm start

Open http://localhost:8000.

If port 8000 is unavailable, or you want to bind a specific host:

HOST=127.0.0.1 PORT=8010 npm start

Project documentation:

  • README.md
  • DESIGN.md
  • docs/runtime-baseline.md

Project Structure

  • src/client/main.ts: bootstrap and orchestration between UI, state, and scene lifecycle
  • src/client/scenes/MainScene.ts: runtime scene composition, rendering, gameplay loop
  • src/client/scenes/runtime/: scene-local runtime systems (CoverageSystem, CollidableIndex, EnemyRuntimeSystem, PaintRuntimeSystem, BombRuntimeSystem, ProgressionRuntimeSystem) plus pure runtime policies
  • src/client/scenes/runtime/RuntimeSceneBridge.ts: key-based runtime scene lookup helper for restart/live-update orchestration
  • src/client/systems/EditorSystem.ts: editor interactions and object manipulation
  • src/client/systems/editor/EnemySpatialIndex.ts: spatial index for scalable enemy selection/placement queries in editor mode
  • src/client/systems/editor/EnemyHandleQuery.ts: extracted enemy handle-hit math for editor resize/wander controls
  • src/client/managers/LevelManager.ts: level lifecycle orchestration, history, catalog navigation
  • src/client/managers/level/LevelSchema.ts: centralized level defaults + normalization/schema parsing
  • src/client/managers/level/GoalNormalization.ts: focused goal-threshold and goal-composition parsing/normalization helpers
  • src/client/managers/UIManager.ts: typed UI event bus and form synchronization
  • src/client/managers/ui/: focused UI modules (GoalCompositionEditor, ObjectInventory, ColorPickerPopover, EnvironmentColorRegistry)
  • src/client/config/SettingBindings.ts: single source of truth for settings input-to-domain mappings (consumed by both main.ts and UIManager)
  • src/client/content/LevelObjects.ts: obstacle/object normalization and spatial helpers for editor/runtime
  • src/client/utils/ObstacleOverrideDefaults.ts: shared obstacle override baseline/default mapping used by schema, UI inspector, and context actions
  • src/client/ai/: enemy behavior contracts, implementations, and registry
  • src/client/ai/EnemyTuning.ts: centralized enemy tuning fallback and runtime distance conversion (used by both editor and runtime)
  • src/client/player/: player behavior contracts, implementations, and registry
  • src/client/physics/: physics adapter contracts and concrete adapter implementations
  • src/client/types/: shared domain, events, and global contracts
  • src/server/dev-server.ts: Express server + browser log ingestion endpoint
  • src/server/logging/: server logging normalization/cache/type helpers
  • docs/runtime-baseline.md: pinned Node/npm policy and local/CI setup workflow
  • test/: Vitest suites for manager/content/registry/runtime-system behavior

Extensibility Model

Add an Enemy Behavior

  1. Add the id in ENEMY_BEHAVIOR_TYPES (src/client/types/domain.ts) so both type checks and schema validation stay in sync.
  2. Implement EnemyBehavior in src/client/ai/behaviors/.
  3. Register it in src/client/ai/EnemyBehaviorRegistry.ts.
  4. Add it to UI controls (if configurable) in index.html, UIManager, and main.ts setting maps.

Add a Player Behavior

  1. Add the id in PLAYER_BEHAVIOR_TYPES (src/client/types/domain.ts).
  2. Implement PlayerBehavior in src/client/player/behaviors/.
  3. Register in src/client/player/PlayerBehaviorRegistry.ts.
  4. Expose tunables in LevelSettings and sync through UI maps.

Add an Obstacle Type

  1. Extend OBSTACLE_TYPES and ObstacleData in src/client/types/domain.ts.
  2. Add runtime definition in src/client/content/LevelObjects.ts.
  3. Provide texture/render handling in MainScene.
  4. Add editor tool wiring in index.html + EditorSystem.

Add / Replace a Physics Engine

Current product direction is one-engine optimization: Arcade physics is fixed as runtime engine, and the editor exposes deep Arcade tuning instead of engine swapping.

If you later need a second engine:

  1. Add the id in PHYSICS_ENGINE_TYPES (src/client/types/domain.ts).
  2. Implement PhysicsAdapter in src/client/physics/.
  3. Register adapter in PhysicsAdapterRegistry.ts.
  4. Add UI/schema wiring only when truly needed.

Add a Runtime Scene System

  1. Put pure, performance-sensitive scene logic in src/client/scenes/runtime/.
  2. Keep the system Phaser-agnostic when possible (state updates and indexing in plain TS).
  3. Inject the system into MainScene during create() with current runtime config.
  4. Add a focused unit test under test/ for the new system.

Current runtime extraction examples:

  • EnemyRuntimeSystem handles enemy attraction, debug drawing, and trail emission.
  • PaintRuntimeSystem handles projectile paint, owner resolution, and coverage/exit activation updates.
  • BombRuntimeSystem handles bomb touch/explosion flow and wall-targeted splash painting with wall-face impact projection.
  • ProgressionRuntimeSystem handles win-state presentation and level-advance flow.
  • EnemyRuntimePolicy, PaintRuntimePolicy, and ProgressionRuntimePolicy contain deterministic pure logic used by tests.

Multi-Level Catalogs

  • LevelManager supports both:
    • single-level JSON payloads (editor convenience)
    • catalog payloads with currentLevelIndex + levels[]
  • Runtime supports next/previous level navigation and per-level identity (id, name).
  • Editor now supports level authoring actions directly in UI: add, duplicate, delete, and JSON load.
  • Save now emits a canonical v3 catalog envelope (schemaVersion: 3, currentLevelIndex, levels) for consistent multi-level workflows.
  • Catalog payloads with unsupported schema versions are rejected during load.

Performance Notes

  • Enemy ground checks use indexed tile lookup (avoids per-frame wall scans).
  • Coverage updates run through CoverageSystem with per-surface ownership accounting (avoids full-grid recounts and repeated same-surface churn).
  • Coverage tracking is idempotent per surface/color: repainting the same surface with the same color does not increase coverage.
  • Coverage paint expiration is surface-scoped with lightweight next-expiry tracking.
  • Drag fill uses occupancy sets (avoids repeated O(n) duplicate scans during area writes).
  • Editor history now supports delta-based undo entries for high-frequency editor mutations (move/resize/fill/erase/settings), reducing full-state clone pressure.
  • Enemy attraction uses squared-distance checks (avoids unnecessary square-root work in hot loops).
  • Paint owner resolution caches player/enemy palette colors per scene runtime instance.
  • Projectile runtime now performs TTL/out-of-bounds recycling to prevent object-pool exhaustion.
  • Paint splats now recycle pooled instances when saturated to keep visual feedback stable over long sessions.
  • Player bullet paint and enemy trail paint now support optional timed fade durations (seconds-based settings) with lightweight in-runtime expiry tracking.
  • Editor selection and hit-testing uses squared-distance checks with shared thresholds.
  • Inspector sync during drag-resize is frame-batched (requestAnimationFrame) to reduce DOM update pressure.
  • Enemy selection/placement uses a grid spatial index to avoid linear scans as enemy counts grow.
  • Enemy handle hit-testing now uses override-aware spatial search distance and avoids per-move full-enemy fallback scans.
  • DOM bootstrapping uses a safe onDomReady gate to avoid missed initialization paths.
  • UI synchronization caches key DOM references and skips no-op form writes to lower inspector overhead.
  • Help modal tab switching is now DOM-scoped to the modal, preventing accidental inspector-tab state mutations.
  • Editor mutations now update scene visuals incrementally in edit mode (move/add/remove/object-fill) instead of full scene restarts on every action.
  • Enemy attraction state now cleanly releases back to non-attracted behavior when attraction no longer applies.
  • Dynamic runtime-safe settings (playerSpeed, playerJump, playerAirControl, playerPaintDecay, playerPaintDuration, enemyTrailDecay, enemyTrailDuration, debugAI, goalTeam, targetPercent, targetThresholds, wallColorDefault, spikeColorDefault, bombColorDefault) now apply live without full scene restart.
  • Dynamic runtime-safe settings now also include Arcade tuning values (gravity, projectile cadence/speed/ttl, player acceleration/drag/jump windows, enemy movement/attraction/jump tuning).
  • Grid/map resize now clamps and deduplicates entity/obstacle geometry to prevent stale out-of-bounds runtime state.
  • Runtime scene bridge resolution now targets MainScene by key rather than scene array index.
  • Phaser runtime dependency is served locally (/node_modules/phaser/...) to remove external CDN reliance in local sessions.
  • Main scene base textures are regenerated only when grid-size-relevant signatures change, avoiding repeated texture churn on no-op restarts.

Type Safety and Validation

  • Strict TS flags enabled (strict, exactOptionalPropertyTypes, noUncheckedIndexedAccess).
  • Supported engine/behavior/obstacle literals are centralized as exported typed catalogs in src/client/types/domain.ts and reused by schema validation.
  • Imported JSON is normalized defensively through LevelSchema.
  • Normalization now clamps map dimensions (MIN/MAX_MAP_TILES), grid size (MIN/MAX_GRID_SIZE), target percent (0..100), and all object/player/exit coordinates into valid in-bounds grid centers.
  • Loaded map dimensions are snapped to the active grid size so imported levels always align to full tiles.
  • Incremental settings edits are normalized through normalizeSettingValue, so direct UI updates cannot write invalid runtime settings.
  • Incremental local-enemy overrides are normalized through shared schema bounds before write, matching global tuning safety.
  • Paint persistence settings (playerPaintDecay, playerPaintDuration, enemyTrailDecay, enemyTrailDuration) are validated and clamped during both import normalization and live updates.
  • Goal threshold settings now support multi-threshold inputs (targetThresholds) with clamped/sorted normalization and legacy targetPercent compatibility.
  • Goal composition settings now support multi-team unlock rules (goalComposition, for example enemy:20, player:20) with normalization and legacy-field synchronization.
  • Enemy identity fields (id, name) are normalized to stable unique values so inventory actions and per-enemy authoring remain deterministic.
  • Arcade tuning settings and obstacle-size settings are validated/clamped in schema normalization and incremental updates.
  • Obstacle color normalization falls back to object default settings (wallColorDefault, spikeColorDefault, bombColorDefault) so non-overridden instances stay linked to global defaults.
  • Scene color conversion is now safely validated at call sites (no global Phaser parser patching).
  • Enemy sensing/chase tuning now uses canonical width/height fields only (sightWidth, sightHeight, chaseWidth, chaseHeight).

Engineering Tooling

  • Runtime baseline: Node 24.13.1 LTS + npm 11.8.0 pinned across local and CI.
  • Linting: npm run lint (ESLint flat config with TypeScript rules)
  • Formatting: npm run format / npm run format:check (Prettier)
  • Full local quality gate: npm run check
  • Mutation-testing pilot: npm run test:mutation (targets critical modules; use npm run test:mutation -- --dryRunOnly for wiring validation)
  • CI workflow: .github/workflows/ci.yml runs typecheck, lint, test, build, and format:check

Build Output

npm run build emits:

  • dist/client/**/*.js
  • dist/server/dev-server.js

index.html loads dist/client/main.js. index.html loads Phaser from /node_modules/phaser/dist/phaser-arcade-physics.min.js.

UI/UX Notes

  • Object inspector tabs are context-scoped to the selected object/tool; selecting a bomb exposes bomb defaults in Global and bomb overrides in Individual.
  • Inspector tab choice is stable (no forced auto-switch); local tab falls back to global only when local overrides are unavailable.
  • Global object-default panels now use a consistent Default badge treatment across enemy/player/exit/wall/spike/bomb contexts.
  • Global wall/spike/bomb inspector panels each include a visual color picker with the same palette flow as other object color controls.
  • Individual override panels use a consistent Tunning badge treatment.
  • New paint persistence controls allow configuring permanent vs timed fade behavior for player and enemy paint.
  • Winner-team labels are color-dynamic (derived from current player/enemy palette values), not hardcoded to red/blue text.
  • Goal rules support multiple thresholds (for example 15, 30, 45) with live HUD updates.
  • Goal rules also support composite unlock requirements (for example enemy:20, player:20) with HUD progress shown for both teams.
  • Goal composition editing uses structured rows sourced from current environment colors (player/enemy/obstacle), with a swatch-first popover picker, source labels, and hex backup input.
  • Individual inspector rows expose consistent reset/apply actions; apply propagates to same-type instances and updates object defaults where applicable (for example bomb defaults).
  • Obstacle color edits (global defaults and individual overrides) now apply live without full scene restart, and obstacle textures are neutral so tint changes are visually clear.
  • Bomb splash paint now applies only to wall surfaces within radius and lands on the nearest wall face (not tile center); explosions with no nearby wall leave coverage unchanged.
  • Sidebar is dock-first: top-level panels start in the sidebar, can be undocked by drag, and support per-panel/global layout reset.
  • Docked layout supports sidebar width resize and per-panel height resize; floating panels support width+height resize.
  • Top-level sidebar panels remain collapsible in both docked and floating modes (floating collapse is header-only) and support quick-jump navigation.
  • Inventory panel lists player/exit/enemies/walls/spikes/bombs grouped by type, with per-instance selection sync to canvas selection.
  • Global game settings are organized under one Game Settings section with subsections (World, Goals & Win Conditions, Paint & Fade Rules, Physics & Motion).
  • Color selection now uses an in-app palette popover with an explicit Existing Level Colors list plus custom HSV controls, RGB fields, and hex tools, anchored outside scroll clipping regions.
  • Grid/map size and object dimensions are editable in both tiles and pixels (width/height pairs), with synchronized conversions.
  • Arcade physics is now exposed as a single highly-configurable profile (no engine swap dropdown).
  • Sidebar and header styling were upgraded for clearer hierarchy, stronger focus states, and better visual consistency.
  • Editor controls and Goal Mix rows now follow a consistent WCAG-AA-oriented focus/contrast treatment across light and dark themes.
  • Layout is responsive for tablet/mobile widths (stacked workbench, adaptive controls area, and sidebar adjustments).

Logging

The dev server accepts browser logs at POST /log and writes per-client log files under logs/.

  • Payloads are normalized and validated before write (bounded message/type/client-id/data).
  • JSON body size is capped (64kb) to avoid oversized request pressure.
  • Active in-memory client log-file tracking is pruned by TTL and bounded by max active client count to prevent unbounded cache growth in long sessions.
  • Logging concerns are split into focused modules (LogNormalization, LogCache, LogTypes) for maintainable extension.
  • Server startup is now explicit (startDevServer) and supports test imports without side effects.
  • Endpoint behavior is covered by both unit normalization tests and HTTP integration tests.
  • Scene init/create failures now emit structured client logs with correlation IDs, and /log payload serialization preserves Error details (name, message, stack, cause, code) safely.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages