Guide9 min read10 sections

Dusk compatibility inventory

Engine naming, retained identifiers, storage compatibility, and ownership.

docs/DUSK_COMPATIBILITY.mdSource updated 2026-10-28
Markdown
On this page 10 sections

The engine is Dusk. Darkwind is the reference game built with it. This record lists the places where the old name intentionally survives, and the ownership targets for the rename. The plan is DUSK_IDENTITY_AND_REFERENCE_GAME_PLAN.

The rule is correct ownership, not zero search matches. Each old-name occurrence falls into one class:

  1. Engine branding: changes to Dusk.
  2. Darkwind game identity or content: stays Darkwind.
  3. Compatibility or persistent identity: kept, because changing it would break saves, sessions, wire negotiation or retained builds.
  4. Historical evidence, fixture or credit: kept with its factual meaning.
  5. Incidental internal label: renamed only when a touched file makes it relevant.

#Retained compatibility identifiers (class 3)

Location Identifier Why it remains Check
packages/sdk/index.ts SDK_API = 'darkwind-game-sdk.1' Serialized into portable game releases. Older releases name it. tests/game-sdk.test.ts
packages/behavior/index.ts darkwind-plugin.1 Engine plugin contract version tests/extensions.test.ts
packages/schema/extensions.ts darkwind-extension.1 Installed creator extension contract tests/extensions.test.ts
packages/agent-tools/index.ts darkwind-agent-tools.1 Agent tool contract version tests/agent-tools.test.ts
packages/net/wire.ts darkwind.binary.1.<hash> Negotiated WebSocket subprotocol; retained engines expect it npm run check (generated wire)
packages/simulation/checkpoint.ts darkwind.simulation.1–.7, darkwind.simulation.behavior.1 Checkpoint profiles and legacy readers tests/checkpoints.test.ts
packages/physics/* darkwind-owned-rigid.8, darkwind-owned-scene.1, darkwind-owned-floating.1, darkwind-owned-character.1 Owned-physics checkpoint identities tests/owned-*.test.ts
apps/player/* browser storage darkwind:controls:v1, darkwind:audio:v1, darkwind:visual-quality:v1 Player preferences. Renaming would discard settings. —
apps/player/* browser storage darkwind:development…, darkwind:playtest:…, darkwind:game:…, darkwind:persistent:…, darkwind:crossing:…, darkwind:directory:…, darkwind:room-token, darkwind:lantern-house Saves and return credentials tests/browser/*
apps/editor/main.ts darkwind:editor-key, darkwind:editor-name, darkwind:editor-history-actor Editor access and history identity. Renaming would log builders out. tests/browser/editor-panels.spec.ts
services/routing/welcome.ts darkwind:directory:, darkwind-region: Regional directory and storage keys —
services/persistent/watchdog.ts darkwind:watchdog:ping/pong Inter-process protocol with retained hosts tests/host-watchdog.test.ts
apps/probe, apps/editor recording messages darkwind-take-*, darkwind-series-* Cross-window message types with retained players tests/hosted-recordings.test.ts
services/storage/objects.ts darkwind-backups default bucket Existing backup bucket identity tests/backup.test.ts
PostgreSQL dw_* tables and schemas Existing databases and migrations tests/content-persistent.test.ts
Docker / Compose volumes darkwind-room, darkwind-arrival-v10; service keys darkwind, darkwind-beta Existing physical storage and proxy routes docker compose config
Local data .data/hearth, .data/arrival-art.10, .data/meridian.1 Existing room separation —
Golden fixtures, docs/evidence, archived recordings Recorded strings Frozen historical evidence —

#Operator settings

Every public setting has a canonical DUSK_ name and its legacy DW_ alias. The policy is implemented once, in deploy/dusk-env.mjs, and used by every service and launcher entry point (deploy/dusk-env-bootstrap.mjs), the container entrypoint, the health check, the Vite config and npm run compose:

  1. Only one name present: use it. Presence counts, not truthiness, so empty and 0 are real values.
  2. Both present with the same value: accepted.
  3. Both present with different values: the process stops with an error naming both settings. Values are never printed.
  4. Neither present: DUSK_DEFAULT_<NAME> applies. Images and the local Compose file use this for their defaults, so supplying either name overrides an image default without a false conflict.
  5. After resolution, each process keeps only the DW_ name. Existing code, children and retained older engines read that name, and a launcher's own DW_ override never looks like a conflict.

Settings (each DUSK_X ↔ DW_X): ALLOWED_ORIGINS, ROOM_PASSWORD, ROOM_PASSWORD_REQUIRED, RELAY_PORT, HTTP_PORT, DATA_DIR, STATIC_DIR, ENGINE_BUNDLE, GAME_FILE, GAME_SOURCE, PLAYTEST, PHYSICS_BACKEND, EDITOR_TOKEN, PLAYER_ACCOUNTS, AUTHORING_WORKSPACE, DATABASE_URL, PERSISTENT_ROOM, HOST_PORT, WORLD_DOCUMENT, ROOM_TEMPLATE, ROOM_AUTHORITY, ROOM_PROGRAM, SPAWNED_PLACES, ROOM_ROUTES, ROOM_RSS_LIMIT_MIB, REGION, ROUTER_PORT, OPERATIONS_TOKEN, PLAYER_TRANSFERS, REMOTE_ROOM_HOSTS, ROOM_HOST_PORT, ROOM_HOST_CAP, ROOM_HOST_TOKEN, ROOM_SOCKET, ROOM_CAP, CONTROL_PORT, CONTROL_BIND, CONTROL_TOKEN, POSTGRES_PASSWORD, PHYSICS_TOKEN, PHYSICS_ENDPOINTS, PHYSICS_OWNERS, PHYSICS_CAPACITY, PHYSICS_ALLOW_INSECURE, BUILD_DATABASE_URL, BUILD_POSTGRES_PASSWORD, the BACKUP_* settings, ASSET_PROVIDER_KEY, ASSISTANT_PROVIDER_KEY, CROSSING_VEHICLES, CROSSINGS_DATA_DIR and the HOST_TOKEN_* family. Browser builds accept only VITE_DUSK_PLAYTEST ↔ VITE_DW_PLAYTEST. Test and fixture switches (DW_TEST_*, DW_*_CLIENT_DIR, DW_GPU_PROFILE, DW_BENCH_SECONDS, DW_TERRAIN_*) are not operator settings and keep only their DW_ names. PORT, PG*, NODE_ENV and Playwright options are unchanged.

Build arguments (Dockerfile): DUSK_PLAYTEST/DW_PLAYTEST and DUSK_GAME_SOURCE/DW_GAME_SOURCE. An empty build argument counts as unset; two different non-empty values fail the build.

Compose. The single-container profiles (compose.coolify.yaml, compose.beta.yaml, compose.ferry.yaml, compose.meridian.yaml, compose.yaml) pass both names through unset-preserving. The container resolves them, so DUSK_ names work in Coolify. Values these files fix (port 8787, /data, the static directory and the beta's required passphrase) stay fixed. A different DUSK_ value for one of them is reported as a conflict. The PostgreSQL multi-service profiles (compose.persistent.yaml, compose.rooms.yaml, compose.room-hosts.yaml, compose.cargo.yaml, compose.control.yaml, compose.builds.yaml) interpolate values into non-Dusk images (database passwords, URLs, host tokens), which YAML cannot conflict-check. In Coolify they keep their DW_ names. Locally, npm run compose -- -f <file> … resolves DUSK_ names first. The local host port follows the same rule: DUSK_HOST_PORT through npm run compose, DW_HOST_PORT with plain docker compose.

#Deployment and storage map

Item Value Rename policy
Engine and tool display name Dusk Changed
Game display name Darkwind (in-game credit: Dusk Observatory panel) Kept
Source repository jasona/dusk-engine (renamed from jasona/awaken-engine; GitHub redirects the old URL) Renamed outside this pass
Coolify game service key darkwind (compose.coolify.yaml), darkwind-beta (compose.beta.yaml) Kept: proxy routes and project identity
Named volumes darkwind-room, darkwind-arrival-v10, garden-ferry-v4-room, meridian-v1-room, darkwind-persistent-*, darkwind-regional-* Kept: the same physical data
Container data path, user, port /data, UID/GID 1000:1000, 8787 Kept
Local data .data/hearth, .data/arrival-art.10, .data/meridian.1 Kept
Database names darkwind database and user, dw_* tables Kept
Session signing key, passphrases, origins /data/session-key, operator secrets, public hostname Kept; never logged
Retained engines /data/engine-builds/<hash>, /data/engine-pins Kept byte-for-byte

#Darkwind game identity (class 2)

Darkwind's world ID (darkwind), releases such as lantern-house.1.arrival-10, place, entity and interaction IDs, Elowen's story, the darkwind source import name in npm run author -- import darkwind, fixture names such as garden-ferry, and all of games/darkwind/ stay Darkwind.

#Ownership targets

Milestone Target files Change
R2 tooling UI editor.html, apps/editor/main.ts Dusk World Atelier wordmark and title; draft download name
R2 diagnostics.html, apps/probe/main.ts Dusk Observatory wordmark, title and report name
R2 physics.html, apps/physics-lab/main.ts Dusk Physics Lab wordmark and title; Darkwind fixture labels identify the game
R2 services/relay/server.ts, services/control/main.ts, services/persistent/main.ts, services/routing/pool.ts Startup output names the Dusk service
R3 game boundary apps/player/main.ts Remove Darkwind control, gamepad and copy imports; neutral world variable; injected presentation
R3 apps/player/graphics.ts, graphics.worker.ts, graphics-revision.ts, catalog.ts Traveler model and rig come from the admitted presentation
R3 apps/player/audio.ts Sound graph and frame come from the presentation adapter
R3 services/relay/server.ts No default Darkwind world; callers pass one
R3 services/relay/main.ts, services/persistent/world.ts, services/routing/main.ts Explicit reference-game composition
R4 commands and configuration tools/cli/*.mjs, deploy/*, Dockerfile*, compose*.yaml, .env.example DUSK_* settings with DW_* aliases, npm run dev:darkwind

#Explicit game-import exceptions

npm run check enforces these boundaries (HOST_GAME_BOUNDARIES in tools/cli/check-boundaries.ts), including type and dynamic imports:

  • Reusable player (apps/player/): no module imports games/, except the trusted presentation registry apps/player/installed-games.ts.
  • Services (services/): no module imports games/darkwind/, except the operator composition files services/relay/reference-worlds.ts, services/persistent/world.ts and services/routing/main.ts. The reusable createRelay factory requires an explicit world.

Not covered by that check, by design:

  • Diagnostics fixtures that load named demo content: apps/probe/*, apps/physics-lab/main.ts.
  • Tools, benchmarks and migrations about Darkwind content: tools/cli/*, tools/bench/*.
  • Tests.

#Acceptance record

#R2 — Dusk tooling and engine UI (2/5)

The editor wordmark and title read Dusk World Atelier. Diagnostics read Dusk Observatory, and the physics page reads Dusk Physics Lab, with a "Dusk · owned solver" engine label. The player's F2 panel is headed Dusk Observatory, and the relay and control services print Dusk startup lines. Draft and capability downloads are named dusk-draft-N.json and dusk-capabilities.json; their contents are unchanged. Darkwind keeps its title, wordmark and approved traveler. Editor key, name and history storage keys are unchanged.

Checks (Node 22.23.4, /usr/bin/chromium): tsc --noEmit; owned-physics.spec.ts:2, editor.spec.ts:7 (draft export name) and editor-panels.spec.ts:29 (saved editor identity) pass. editor-panels.spec.ts:10 fails identically on the unchanged baseline under software rendering (#enter stays disabled), so it is pre-existing and is not a rename regression.

Captures (physical GPU, isolated data directory): editor · Observatory · Physics Lab · Darkwind.

#R3 — Explicit game presentation and host boundary (3/5)

The reusable player now hosts a game through GamePresentation (apps/player/presentation.ts), chosen by the trusted registry apps/player/installed-games.ts from the admitted world ID. Darkwind's story, welcome, objectives, journal, satchel text, sound, controls and approved traveler moved into games/darkwind/presentation.ts. Keeper-story detection was removed. Other games get the neutral Dusk presentation. The traveler profile reaches the main-thread renderer, the render worker (per created generation, so device recovery reuses it) and graphics revisions and portals. Shared default controls live in packages/input/defaults.ts. They keep the darkwind.player.1 map ID, because saved rebinding profiles are keyed by it. createRelay requires an explicit world. The relay picks reference worlds in services/relay/reference-worlds.ts.

Checks (Node 22.23.4): npm run check (types, boundaries including the new host rule, generated wire); native boundaries, player-graphics-revision, net, net-interest, relay-shutdown, static-notices, engine-pinning, playtest-release, game-sdk and development-room tests pass (35). Browser audio, gamepad and most of player.spec pass under software rendering. V7: tests/meridian-browser.test.ts (two-player puzzle, travel, reload and editor publication) passes on the physical GPU.

Pre-existing failures, identical on the R2 baseline af9087f under software rendering and not caused by the rename: 8 in player.spec.ts (including the 53 / 4 GPU allocation that predates the Vita traveler), 2 in simulation-recovery.spec.ts, 1 in portal-rendering.spec.ts, the jump hint in controls.spec.ts, and meridian-browser.test.ts with SwiftShader (#enter stays disabled). Recorded for follow-up, not fixed in this pass.

Captures (physical GPU): Darkwind welcome · Darkwind journal · Meridian world · Meridian journal.

Known bound: the static index.html is neutral ("Dusk") until the admitted game's presentation applies, so link previews of a Darkwind deployment say "Dusk".

#R4 — Commands, compatible configuration and deployment readiness (4/5)

npm run dev:darkwind starts Darkwind's polished arrival (same as dev:art, which remains). dev, dev:editor, dev:meridian and the other commands are unchanged. Launchers print "Dusk World Atelier (private)". npm run compose resolves DUSK_ settings before Compose interpolation. Every service and launcher entry point, the container entrypoint and health check, the Dockerfiles' build arguments and defaults, and the Vite config follow the policy in Operator settings.

Checks (Node 22.23.4): npm run build (check, player, workers, editor, server, author, accounts, retained engine) passes. tests/dusk-env.test.ts (10) covers canonical-only, legacy-only, equal, unequal (no values in errors), empty and 0, image-default provenance, HOST_TOKEN_*, the Vite pair, the entrypoint locking the resolved directory, the independent health probe following a canonical-only port, and a bootstrapped launcher's child reading the legacy name. deployment, editor, persistent-world-source and room-routing pass (24 PostgreSQL cases skipped). Builds with VITE_DUSK_PLAYTEST and VITE_DW_PLAYTEST produce the same ferry selection, and a conflicting pair fails the build.

Host smoke of the built production server through deploy/entrypoint.sh: canonical-only and legacy-only settings both start, lock the resolved directory, ignore the image-default directory and pass deploy/healthcheck.mjs. A conflicting passphrase pair exits 78 before locking, with no values printed. A copy of the existing .data/hearth room (revision 1) loads under DUSK_DATA_DIR, admits a traveler and keeps its signing key. The isolated arrival dev stack starts with DUSK_-only settings. Effective Compose configuration was inspected for legacy-only and canonical-only Coolify settings: the volumes are still darkwind-room and darkwind-arrival-v10 at /data. This is static configuration, not hosted restart evidence; Docker image builds were not run here.

Found and fixed during this milestone: the resolver's command-line guard matched inside bundled server entry points and exited the server. It now also requires its own filename.

End of Dusk compatibility