Every product on CommsLink is designed and shipped to production by an AI — live, most days. This is the raw record, generated straight from the commit history. No hand-picking, no polish: 2,358 ships and counting.
R82: EVEN OUT THE SEA FLOOR — runtime-detach the ~2349 deep 5x5x11 heightfield boxes (the uneven ocean floor, confirmed as the deepest meshes via the depth query). Sub reads seabedDepth() field not these visual boxes, so safe. Biggest single object-count cut. Reversible via EVEN_SEA_FLOOR flag
R81: DEEPEST-mesh diagnostic (user's 'closest to sphere centre = ocean floor' insight) — log the lowest-Y meshes + identity + parent to finally ID the sea-floor system
R80: pinpoint the 5x5x11 box (2349x) — log a sample's parent chain + world pos to name its creation site for instancing
R79: GEOFREQ diagnostic — count meshes by geometry signature (type + dims) to find the most-repeated shape = the highest-ROI InstancedMesh target (Win 2, step 1a)
R78: composition diagnostic — add group world-position + first-child box dims to the name hint, to locate/identify the ~10 uniform ~270-object box-pools (enemy hulls are only 2 boxes, so these aren't ships)
R77: parked planes → ONE merged vertex-coloured mesh each (was ~15 box parts). makeParkedPlane now wraps _buildParkedPlaneParts + _mergeGroupToMesh. Cuts ~14 objs/plane × ~20-26 always-in-scene planes = the bulk of the 897-object carrier. All _park usages are opaque Object3D ops so a Mesh drops in cleanly. Fallback to raw group if merge fails
R76: name the anonymous scene groups in the composition diagnostic (walk to first named descendant / geometry type) — identify what the ~6400-object diffuse bulk actually is
R75: scene-composition diagnostic — log total scene objects + top-level groups by descendant count, to find the REAL object-count driver (buildings were only 472/11000)
R74: add MERGE diagnostic — log mergedCities/hiddenBuildings so we can see whether the city merge is actually running (r73 telemetry showed no draw/obj drop)
R73: CITY MERGE (client-side) — bake each city's static building bodies + roof caps into ONE vertex-coloured mesh via existing _mergeBaked (per-city, sphere-safe convention). Auto-excludes dynamic objects (roof heli, hangar planes, NPC crew, lights = separate objects). Throttled re-merge on build/raze. Cuts draw calls + object count + per-frame sphere-bend CPU. v1: no night-dim on merged cities. Toggle CITY_MERGE
R72: remove all building BURNING effects (updateBuildingFx fire/smoke/ember neutered; scorch color removed from damage + heal). Damage is HP-only now; buildings stay their base colour → visually static → mergeable. Step 1 of city-merge
R71: CPU/GPU readout in the debug HUD. main.js brackets its animation loop → window.__c00cpuMs (EMA JS frame time). Engine HUD shows 'CPU Xms · GPU~ Yms CPU-BOUND/GPU-BOUND' (GPU ≈ frame − CPU, valid below the 72Hz cap) + logs cpu/gpu to telemetry. Settles fill-vs-sim without guessing
R70: REVERT world culling (r69) — data proved it did nothing for perf (city stayed 1656 draws, objs/fps unchanged) while hiding faintly-visible fogged buildings. FPS is fill/CPU-bound (8fps at 240 draws), not draw-bound — draw culling was the wrong lever
R69: WORLD CULLING phase 1 — cullIslands() hides city buildings that are geometrically invisible: below the planet horizon (deck/air/orbit — central angle vs viewer+object horizon half-angles) or beyond fog.far. three.js only frustum-culls (still draws everything in the view cone behind the horizon/fog). Targets the '1600 draws toward the city, ~150 visible' gap. Per-island, ~10Hz, state-change only
R67: FIX geometry leak — missile flame built a NEW ConeGeometry per shot (weapons.js:92) and cleanup (line ~302) only scene.remove'd it, never disposing → geometries leaked ~200/min under AI missile fire. Now a single cached _mslFlameGeo shared by all missiles (nuke pattern). Confirmed via telemetry: geometries climbed while objs stayed flat = churn without disposal
R66: perf telemetry moved into the shared engine (one impl for /chat + Carrier00, host-tagged); removed Carrier00's duplicate host-side sampler. All debug tracking now gated behind the debug HUD being shown
R65: (1) FIX worn avatar — Carrier00 never called engine.setUserAvatar, so the player had no body; now loads /models/aruishi.vrm (or localStorage cl_user_avatar) first-person. (2) PERF telemetry — every 2s in VR, POST FPS/ms/draws/tris/objects + head yaw to server log to correlate framerate with view direction
VR perf: drop MSAA (antialias:false) on the main renderer — heavy VR fill cost on ocean/sky, can't be toggled per-session (context attr), so dropped globally. Pairs with foveation (r61). Tradeoff: desktop edges jag
R59 WHOLESALE integration port: extract chat's COMPLETE client wiring (the 40-case movement director + every avatar socket handler + Q&A + lip-sync) into ONE shared module (avatarSocketBridge → avatarbridge.mjs). chat.js mounts wireAvatarSocket(socket, getEngine) — the whole feature set wired at once, not per-host. Removed Carrier00's overlapping hand-wired handlers. This is 'run chat's integration', not fix-one-function-a-day. (AvatarPanel still has its inline copy — delegating it to the shared module is the paired de-dup.)
R58 UNIFY the env — no more fork: engine.setEnv(env) hands Carrier00's env (chat's environment.ts, fed our planes) to the engine so its execVoiceCommand runs Computer env-commands on THAT one env. Relaxed the AR-only guard (!this.env||!liveAlign → !this.env; equivalent in /chat). onVoiceText routes ALL commands to the engine's handleVoiceLine now — env, exit, Q&A, reports all chat's code, one env
R57 THE FIX: add the voice_cmd listener chat.js was missing. On Quest, voice is server-side; the server detects 'Computer' + emits voice_cmd with the command — Carrier00 never listened, so every Computer command was dropped. Now routes voice_cmd → onVoiceText → env/exit/Q&A. This is why nothing worked regardless of client changes
R56 FIX the voice-command break I caused: my routing sent env commands to engine.handleVoiceLine, which EATS them (env gated in host mode → 'works in AR only' → returns true → never falls through). Now env commands ('make X visible') → Carrier00's working env handler; only exit/Q&A/bug/feature/chime → the engine
Use the EXISTING build number: revert my duplicate C00_BUILD slop; bump the engine's GHOST_BUILD r54→r55 and surface it in Carrier00's mount log + VR button. No new constant — the build number that was always in the engine
BUILD B49: add visible build number — big in the re-enabled in-VR debug HUD + on the VR button. Confirms the headset is on the latest build (not a cached one). Bump C00_BUILD every deploy
Carrier00 BUILD B49: visible build number in the in-VR debug HUD + VR button (stale-cache check)
Fix STT regression: setPhysicalHandler was forwarding EVERY engine physical event (proximity/grab per frame) to the socket, flooding it and starving the voice STT stream → no transcripts. Filter to only the low-frequency command/report events (bug/cmd_arm/report/dismiss/env_state)
Filter setPhysicalHandler to low-freq events only — fixes voice STT starved by the physical-event flood
Route voice to chat's handleVoiceLine (Computer chime + Q&A + bug/feature reports + exit) via the mounted engine; wire setPhysicalHandler to the socket
Route voice to chat's REAL command handler: transcripts → engine.handleVoiceLine (Computer wake word + chime + Q&A + bug/feature reports), engine.setPhysicalHandler → chat socket (bug_arm/bug_report/cmd_arm reach server). 'Computer exit' now hits the engine's exit command. Env commands fall back to Carrier00 onVoice until the engine's env is un-gated. NOT a rebuild — chat's code
Fix duplicate XR setup: vr.js was adding its OWN controllers/grips/hand models on the same shared XRHand joints the engine also sets up → two XRHandModelFactory models z-fighting (the 'second room' glitch + broken hands). Removed vr.js's set; the mounted engine owns XR input. Also log dolly child names for diagnosis
Remove duplicate controller/hand setup in vr.js (was z-fighting the engine's) — fixes room glitch + hands
Fix engine-mount invisibility: point the engine's scene at the host DOLLY (bend-exempt) so Eve/hands/wrist aren't swept by Carrier00's floating-origin bend. Add frame-error logging (log first throw, was swallowed) + post-mount diagnostic (presenting/dollyKids/avatar)
MOUNT THE REAL CHAT ENGINE: Carrier00 now runs VrmEngine itself (vrmengine.mjs = the entire 7k-line engine bundled, three+three-vrm external) instead of hand-wired kits. vr.js: new VrmEngine({renderer,scene,camera,dolly}) → init() → loadAvatar() → frame() per tick; chat.js feeds pushChatLine + avatar_speak→speakAudio. VrmEngine made host-agnostic (constructor/init adopt an external world; onXRStart uses host dolly + skips chat room; frame() for host loops) — /chat unchanged (all host-guarded). Eve, grab/touch, wrist all from chat's actual code. Replaces companion.js/roomui.js
Extract wrist intent-gate from VrmEngine → shared WristGate (uikit). The 'raise fist ~2s to summon, hide when arm drops' rule was welded into VrmEngine; moved it verbatim into wristUI.ts (WristGate), VrmEngine now delegates, Carrier00 imports the SAME gate. No fork. Carrier00 wrist now appears by the exact chat rule (fist detection via curled fingertips; controllers: raised is enough)
Native UI port: wrist/chat/debug are now the REAL chat widgets (uikit.mjs = bundled wristUI+chatPanel+debugHud). roomui imports uikit, drives the generic native wrist with Carrier00's button spec (Chat·Avatar·Debug·Report·Exit); native ChatPanel (push from chat_message) + native head-locked DebugHud. Deleted rebuilt wrist/chatpanel/debughud.js; kept React-adapted picker+feedback. Wrist is poke-driven (native) like chat; laser only for the far floating panels. import-map: uikit
Carrier00 VR: aim-ray laser + fingertip dots so you can see where you point + click the wrist/avatar buttons
VR interaction: add a visible aim ray (laser) from each hand/controller + a bright fingertip dot, so the user can SEE where they're pointing and pinch/trigger to click wrist/panel buttons (they couldn't see their own hands to aim)
Native furniture feed + fix peripheral passthrough. (1) vr.js reads frame.detectedMeshes → builds furniture groups → env.styleFurniture (chat's exact impl), so 'Computer, make the <object> visible' reveals real scanned furniture. (2) main.js sky dome radius 5900→1000: it was at/beyond the XR far plane (far=6000) and getting clipped at the FOV periphery → raw passthrough; 1000 is well inside far like chat's 540/650
Native furniture feed (Computer show objects) + fix peripheral passthrough (sky dome was far-clipped)
Fix avatar-picker access + Computer commands: 'Computer, avatar' opens the picker (companion + YOUR avatar tabs) via voice — reliable when the wrist unit isn't reachable; also 'Computer, exit' (ends VR), chat/report/debug/hide. Wrist-anchor diagnostic logs whether a hand-joint/grip is in reach
'Computer, avatar' opens the avatar picker by voice + Computer exit/chat/report/debug/hide; wrist-anchor diagnostic
PHASE 2 batch: real Eve behavior + full room UI. companion.js drives the extracted CompanionRig (companion.mjs = Chat's VrmEngine companion logic, bundled) — movement/gaze/lip-sync/gestures; avatar_speak → rig.speak (plays+lipsyncs). Room UI (roomui.js + src/ui/*): chat panel, avatar pickers (cl_ai_avatar/cl_user_avatar), wrist unit, debug HUD, voice-dictated bug/feature reporter. Computer commands re-routed to the room engine. import-map: companionkit
Place Eve in front of the player's gaze + log her position/size (she loaded but wasn't visible)
Eve placement: stand her 1.5m in front of where the player is LOOKING at load (not a fixed guardian-forward spot that could be behind them/in a wall), face the player, disable frustum culling, and log her world position + height (to catch scale issues)
Carrier00 Phase 2a: render Eve's VRM body in the room (three-vrm from CDN, r0.180)
PHASE 2a: render Eve's VRM in the room. companion.js loads the companion's chosen .vrm (localStorage cl_ai_avatar, same origin as /chat) via @pixiv/three-vrm (CDN, three external, now r0.180) + three/addons GLTFLoader; stands her ~1.3m in front on the floor, under the VR rig (fixed in room, not sphere-bent), vrm.update each frame. Lip-sync next
Carrier00 VR: remove thumbstick, auto bow-alignment only
Remove the thumbstick nudge — auto-snap only (no manual control, no bloat). worldYaw = _fwdYaw (auto bow-to-wall alignment)
Carrier00 VR: re-enable AUTO bow-to-wall alignment (main.js now reads the auto _fwdYaw; duplicate-room confound is fixed)
Re-enable AUTO carrier-bow alignment (was only broken because main.js read the manual thumbstick value instead of the auto _fwdYaw). worldYaw = _fwdYaw (auto-snap the front wall to the bow at rendered -Z) + optional thumbstick nudge. The duplicate-room bug that made this look broken before is now fixed, so the snap holds
Carrier00 VR: right thumbstick rotates the naval world so you align a wall to the carrier bow yourself (persisted). No more auto-snap sign guessing
Carrier-bow alignment = USER-CONTROLLED (right thumbstick), persisted. Rotate the naval world to line a wall up with the carrier's bow yourself; saved to localStorage + restored per session. Replaces the auto-snap I kept getting the sign wrong on. Applied as a yaw premultiply on the eye-frame rotation (turns the world, not the room)
Upgrade Carrier00 three.js r0.160 -> r0.180 (import-map). Aligns with CommsLink (three ^0.180) so roomkit runs native + unblocks the VRM avatar port (@pixiv/three-vrm 3.5.3 needs r0.180). r0.160 already had the color-management + physical-lights defaults, so this is incremental — no breaking APIs in Carrier00's code
Upgrade three.js r0.160 -> r0.180 (aligns with CommsLink, unblocks VRM avatar)
Voice is just-talk (mic opens on room-join, no button) like /chat
Voice = just talk (like /chat): open the mic on room-join instead of push-to-talk (removed the controller-trigger gating); stop the mic on VR exit
Carrier00 Phase 1: chat/voice/AI via a 2nd socket to Chat's namespace + presencekit (Chat's real voiceCapture+tts). Hold trigger to talk
PHASE 1 presence port: Carrier00 becomes a CommsLink Chat client. Opens a 2nd socket to the chat DEFAULT namespace (same JWT as the /carrier00 game socket), auto-joins the player's room; push-to-talk (hold controller trigger/pinch) streams 16kHz PCM via Chat's real voiceCapture → server Amazon Transcribe → transcript returns as chat_message → the room's AI agent auto-replies (1-agent-1-human) with Polly audio → playAudioBlob speaks it. presencekit.mjs = bundled voiceCapture + tts (Chat's actual pipeline, not rebuilt). Lazy-imported; import-map adds presencekit
VR sky dome: opaque sky above the ocean horizon (fixes passthrough-above-horizon — scene.background is null for passthrough so nothing was drawn there). Backdrop on the player rig, renderOrder -50 + depthWrite off, masked by the room occluder (passthrough inside), shows through windows above the sea; color tracks _skyC. Also guard scene.background.copy in updateDayNight (was throwing on null bg in VR)
Carrier00 VR: opaque sky dome above the horizon (fixes passthrough sky); guard updateDayNight null background
VR hands: render tracked hand joints via XRHandModelFactory (getHand was an empty joint space = invisible hands with hand-tracking). Lazy-imported so it can't break the desktop game
Carrier00 VR: render hand-tracking joints (hands were invisible — getHand had no joint models)
ROOT CAUSE of the recurring VR '2nd room': loadCommandRoom is async (awaits the scan fetch) and is called on startup + every 400ms — if the fetch takes >400ms, two calls both pass the '_commandRoom null?' check and both build a c00CommandRoom, but only the last is tracked+hidden; the orphaned duplicate stays visible = the 2nd room (intermittent, timing-dependent). Fix: synchronous _roomLoading guard before the await (no more duplicates) + hide ALL c00CommandRoom copies by name in VR (clears any existing orphan without a reload). Confirmed via ancestor-aware NEAR probe: 2nd room = c00CommandRoom at 0.1m
Carrier00 VR: fix the recurring 2nd room — loadCommandRoom async race made a duplicate scanned room; add a load guard + hide all room copies by name in VR
Carrier00 VR: REVERT the wall-snap alignment (it broke the view again) — back to the stable 2nd-room-gone state
Align room to carrier: snap the naval world's yaw to the front wall's outward normal (computed from live walls) so a window squares to the bow — instead of aligning to the guardian's arbitrary forward axis (the ~27deg skew). Frozen once per session, applied as a yaw premultiply on the eye-frame rotation
Carrier00 VR: snap the naval world to the room's front wall (fixes the ~27deg room-vs-deck skew so a window faces the bow squarely)
Carrier00 VR: hide all bridge superstructure (incl. the default bridge that wasn't hidden) so it stops rendering on top of the player as a 2nd room; ancestor-aware diagnostic probe
Fix VR '2nd room': hide ALL bridge superstructure in passthrough (the default bridge _bridgeInteriorMeshes was only hidden when a command room loads, so in VR it rendered at the bridge = on the player after the floating-origin). Also hide captainFig/engineers there. Deck/hull stay (ship seen through windows). Made the diagnostic probe ancestor-aware (was counting hidden _commandRoom children as visible = false positive)
Add one-time VR root-cause probe: after the eye-frame transform, log every visible mesh within 18m of the player + its parent chain (c00vrlog 'NEAR...'), to identify the '2nd room' by system instead of guessing
One-time diagnostic probe — log visible meshes near the player in VR to identify the overlapping 2nd room
Fix VR room rotated relative to the carrier: fold the carrier heading (_fcq) back into the eye-frame rotation (_sqInv = (_sq·_fcq)^-1, matching the old rig orientation). Without it the naval world's yaw tracked the carrier's sphere-longitude instead of its bow, so the room read as rotated relative to the carrier while position mapped straight
Carrier00 VR: fix room-rotated-relative-to-carrier — fold the carrier heading back into the eye-frame rotation so the bow is a fixed room direction
Carrier00 VR floating-origin: render the naval world in the eye frame so the carrier bridge sits at the player and the sea curves away under them (was parked 25km out). Ocean+cloud shells transformed; far widened to 6000. Look through a cut window → the ocean/carrier
VR floating-origin: render the bent naval world in the eye's local frame (pos=_sqInv·(bent−_scp), quat=_sqInv·bent) so the carrier bridge sits at the player origin and the ocean curves away under them — instead of parking the dolly 25km out. Ocean+cloud shells transformed too; camera.far widened to 6000 (env.activate set 650 for chat's close world). XR-gated; naval world masked by walls except through the cut windows/doors = the 'see the sea' payoff
Hide the engine's chat outdoor world (trees/sky — built as a side effect of floorCentroid) so the naval world shows through openings; restrict voice commands to windows/doors/passthrough (time/weather/day-night are server-driven, mirror/light are chat-only)
Carrier00 env fixes per user: (1) hide the engine's chat outdoor world (env.world = trees/sky/ocean, built as a side effect of passing floorCentroid) each frame — the naval world is what shows through the openings, not the chat beach; keep the occluder shell. (2) restrict voice commands to opening/visibility/list — time/weather/day-night are SERVER-driven for all players (never per-client), mirror/light are chat-only
Wire voice commands: mic (Web Speech API) → 'Computer, …' → the SAME parseEnvCommands grammar + env.execute (gaze raycaster from the headset). Player can now cut windows/doors + toggle passthrough by voice, looking at the wall. roomkit re-bundled from roomkit-entry.ts to export parseEnvCommands; iframe gains microphone permission
Fix saved window/door placement — compute the real floor centroid+polygon from the live floor plane and pass to env.syncPlanes (was null, misplacing saved openings). Openings come from shared /chat localStorage
Fix saved window/door placement: compute the real floor centroid + polygon from the live floor plane and pass to env.syncPlanes (was null → the engine keyed every wall opening at distance 0, misplacing saved openings onto the wrong surface). Openings come from the shared cl_env_state_v1 localStorage (same origin as /chat)
Fix roomkit load — add three/examples/jsm/ to the import-map so the bundled engine's Reflector import resolves (dead-code mirror on r0.160). EnvironmentEngine now loads
Fix roomkit load: map three/examples/jsm/ in the import-map so the bundled engine's Reflector import resolves (r0.160, dead-code mirror). EnvironmentEngine failed to load without it
Wire in CommsLink's REAL room engine (roomkit.mjs = bundled environment.ts). VR now uses EnvironmentEngine fed live detected planes for the occluder shell (+ window/door cuts + voice passthrough toggles), replacing the stopgap. Lazy-imported so the desktop game is unaffected; renderWrapped skips envShell/envWorld from the bend
Wire in CommsLink's real room engine: vr.js lazily imports EnvironmentEngine from roomkit (bundled environment.ts), instantiates + activates it, and feeds it LIVE detected planes each frame (updateLiveScene) — the actual Chat occluder shell + window/door cuts + voice passthrough toggles, replacing my stopgap buildOccluder. import-map maps 'roomkit'→./roomkit.mjs; renderWrapped skips envShell/envWorld from the sphere-bend so the shell stays glued to the real room at the local-floor origin. Lazy import so it can't break the desktop game
Carrier00 VR room cleanup: remove the in-VR debug panel + hide the FPS rifle viewmodel in the passthrough command room — now it's just your real room
VR room cleanup: remove the in-VR debug panel (server log is enough) and hide the FPS rifle viewmodel in the passthrough command room. Now it's just your real room
Carrier00 VR passthrough room: rig pinned at the local-floor origin (zero offset) so headset==real-room pose; depth-only occluder from the scan masks the naval world so the Quest cameras show your REAL room; opaque virtual room hidden in VR (kept for desktop). Naval world culled for now — returns through windows + floating-origin next. Fixes 'saw the digital room, wrong location'
Fix: remove duplicate fetchScan in room.js (revert had kept the earlier copy)
VR passthrough room (increment 1): pin the rig at the local-floor origin (zero offset) so headset pose == real-room pose; add a depth-only occluder (buildOccluder) from the scan so the naval world is masked and the Quest cameras show your REAL room; hide the opaque virtual command room in VR (kept for desktop). Naval world sits far at the bent bridge (culled) for now — comes back through windows + floating-origin next. Fixes 'saw the digital room, wrong location'
Carrier00 VR step 0a: passthrough AR — flip the XR session to immersive-ar with transparent clear so the player stands in their real room with the naval world around it (desktop untouched, VR-gated). Foundation for the occluder room shell + windows/doors, reusing CommsLink's engine on r0.160
VR step 0a: passthrough. Flip the XR session from immersive-vr (opaque) to immersive-ar with a transparent clear + null background, so the player stands in their REAL room (Quest cameras) with the naval world rendered around it. Desktop untouched (all VR-gated). Occluder shell + windows/doors (0b) come next — reusing CommsLink's environment.ts on r0.160
Plop the ACTUAL scanned room onto the pylon — render the real SpaceScan geometry (walls/floor/ceiling from plane polygons, furniture from object meshes) exactly as captured, recentred onto the command pylon at its true dimensions. No reconstruction/box+blocks. No-scan players get the standard box room. Deck/pylon sized to the scan
Plop the ACTUAL scanned room onto the pylon (not a reconstructed box+blocks): buildScannedRoom renders the real SpaceScan geometry — walls/floor/ceiling from the plane polygons (ShapeGeometry + plane matrix) and furniture from the object meshes (vertices/indices + matrix) — recentred to the floor bbox centre so it sits on the command pylon at its true dimensions. Deck/pylon sized to the scan bbox. No-scan players get the standard box room. fetchScan returns raw scan; dimsFromScan exported for sizing
Command room mirrors the player's scan — render their scanned furniture (bed/desk/etc.) as recentred bounding-box blocks from the SpaceScan objects, so the room reads as their actual room. Browser-game feature; VR renders it
Room mirrors the scan: render the player's scanned FURNITURE as recentred bounding-box blocks (from SpaceScan objects — center transformed by the object matrix, sized by extents), so the command room reads as their actual room. Browser-game feature; VR just renders it
Keep browser + VR identical — island tower removed from ALL carriers at build; every player gets a command room (their scan if saved, else the standard room) instead of conditionally only scan players; engineers on deck for everyone. Command room is a browser-game feature; VR is just the render adapter
Keep browser + VR identical (no fork): remove the island tower from ALL carriers at build (carrier.js), and mount a command room for EVERY player — their scan if saved, else the STANDARD room — instead of conditionally replacing only for scan players. Command room is a browser-game feature on the carrier; VR is just the render adapter on top. Engineers home to the deck for everyone
Room cleanup: hide the carrier's island tower voxels (the tall block through the room's starboard side) via Carrier.hideIsland() when the scan replaces the bridge; move engineer home spots from the mid-deck cluster (z50, in the room) to the port deck line aft of the command island (where deck crew stand)
Command island cleanup (hide tower mast + rotating radar dish + beacon + helm/nav panel when scan replaces the bridge; captain moved to the deck; skinnier support column) + STEP 2: VR player now stands INSIDE the command room (VR eye moved to the room floor at the bridge, rig aligned to carrier heading so you face the front window)
Command island cleanup + VR player stands IN the room. Cleanup (when scan replaces the bridge): hide the tower mast, rotating radar dish (the white ball) + beacon, and the helm/nav panel; move the captain down onto the deck; skinnier support column (0.6x room, reads as a pillar). STEP 2: VR eye moved from carrier centre to the command room floor (bridge world pos) and the rig aligned to the carrier heading, so the headset stands inside the room facing the front window (bow)
Generated 2026-07-16 from git across all CommsLink repos · page 1/6, showing 1–100 of 581 Carrier00 ships · complete record: /changelog.txt · /changelog.json.