feat(viewer): add OpenWorlds atlas surface - #130
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📜 Recent review details🧰 Additional context used🧬 Code graph analysis (1)viewer/tests/test_atlas_surface.py (1)
🔇 Additional comments (3)
📝 WalkthroughWalkthroughThis PR transitions the OpenWorlds map from client-modeled state to an engine-owned atlas read model. The backend projects snapshots via build_atlas_surface() and exposes /atlas-surface; the frontend polls that endpoint, derives map/time/travel state, renders AtlasMap/AtlasSidebar, and posts travel/camp actions back to the engine. ChangesAtlas Surface Feature
Sequence Diagram(s)sequenceDiagram
participant UI as ScreenMap
participant Fetch as GET /atlas-surface
participant Engine as Engine/Snapshot
participant Sidebar as AtlasSidebar
participant Move as POST /move
UI->>Fetch: GET /atlas-surface (query from campaign)
Fetch->>Engine: Read campaign snapshot
Engine-->>Fetch: Snapshot data
Fetch-->>UI: Atlas payload (locations, edges, travel_options, markers, strategic)
UI->>UI: Update surface, time, selectedId
loop Poll every 7s while visible
UI->>Fetch: GET /atlas-surface
Fetch-->>UI: Updated atlas payload
UI->>UI: Refresh derived entities
end
Sidebar->>Move: POST selected travel option + campaign
Move->>Engine: Execute move
Engine-->>Move: Result
Move-->>Sidebar: Success/Failure (toast)
Sidebar->>UI: Request refresh
UI->>Fetch: GET /atlas-surface
Fetch-->>UI: Updated location/state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@viewer/server.py`:
- Line 1450: The sort key lambda uses an ambiguous parameter name `l`; rename it
to a descriptive identifier (e.g., `entry` or `item`) in the call to out.sort so
the key becomes key=lambda entry: (not entry["current"], entry["name"]) to
satisfy E741 and improve readability — update the lambda in the out.sort(...)
invocation accordingly.
- Around line 1600-1605: The list comprehension that builds the "tags" field can
raise TypeError when row.get("tags") returns None because it iterates before the
isinstance check; fix by first assigning tags_list = row.get("tags") and then
using an explicit guard (e.g., tags_list = tags_list if isinstance(tags_list,
list) else []) and finally build tags via [_text(t) for t in tags_list if
_text(t)]; update the dict construction that sets "tags" to use this safe local
tags_list and keep using the _text helper for each element.
- Around line 1444-1448: The list comprehension for "connections" can raise
TypeError when row["connections"] exists but is None; update the code that
builds "connections" (around use of row, _text, visible_ids, and _atlas_tags) to
ensure iteration only happens over a sequence—e.g., first normalize connections
= row.get("connections") or [] (or otherwise guard with isinstance before
iterating) and then use [_text(c) for c in connections if _text(c) in
visible_ids]; this ensures None is treated as an empty list and avoids the
TypeError.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9b20d01e-31ed-48fd-816a-2e142255fba8
📒 Files selected for processing (4)
viewer/openworlds/screen-map.jsxviewer/server.pyviewer/tests/test_atlas_surface.pyviewer/tests/test_openworlds_static.py
📜 Review details
🧰 Additional context used
🧬 Code graph analysis (1)
viewer/openworlds/screen-map.jsx (1)
viewer/openworlds/chrome.jsx (6)
Panel(246-261)Divider(182-189)Placeholder(205-214)Pill(201-203)BrassButton(237-244)SectionTitle(191-199)
🪛 Ruff (0.15.14)
viewer/server.py
[warning] 1420-1420: Use a list comprehension to create a transformed list
(PERF401)
[error] 1450-1450: Ambiguous variable name: l
(E741)
🔇 Additional comments (26)
viewer/server.py (8)
1371-1396: LGTM!
1399-1410: LGTM!
1413-1421: LGTM!
1454-1510: LGTM!
1513-1543: LGTM!
1612-1649: LGTM!
2770-2775: LGTM!
2980-3005: LGTM!viewer/tests/test_atlas_surface.py (4)
1-12: LGTM!
15-148: LGTM!
150-168: LGTM!
170-206: LGTM!viewer/tests/test_openworlds_static.py (3)
108-117: LGTM!
430-480: LGTM!
482-513: LGTM!viewer/openworlds/screen-map.jsx (11)
1-11: LGTM!
13-46: LGTM!
48-79: LGTM!
81-102: LGTM!
104-132: LGTM!
134-148: LGTM!
150-233: LGTM!
235-324: LGTM!
326-404: LGTM!
406-428: LGTM!
430-508: LGTM!
Summary
Refs #117.
Adds the OpenWorlds atlas/map rollout slice as a viewer-owned read model bound to the exported Map screen.
GET /atlas-surface.viewer/openworlds/screen-map.jsxto/atlas-surfaceinstead of prototypestate.locations.POST /move.Architecture Notes
The atlas remains a read/adaptation layer:
build_atlas_surface(...)derives from the engine-owned campaign snapshot./movepayloads such as{ kind: "do", text: "Travel to Rain Market" }.Files To Review
viewer/server.pybuild_atlas_surface_atlas_known_locations_atlas_travel_options_atlas_strategic/atlas-surfacerouteviewer/openworlds/screen-map.jsxatlasSurfaceFromCampaignScreenMapAtlasSidebar/movetravel submission pathviewer/tests/test_atlas_surface.pyviewer/tests/test_openworlds_static.pyValidation
Local validation from
/Volumes/LEXAR/repos/ClawDnD-openworlds-map-surface:Rendered smoke:
Then Chrome/Playwright against
http://127.0.0.1:18767/openworlds/, keyboard shortcutm:Basilisk GateandRain Marketrendered.Hidden Cryptdid not render.Rain MarketrenderedFind the Rain SellerandSapper Cell Regroups.Screenshot artifacts:
/Volumes/LEXAR/Codex/clawdnd-atlas-surface-smoke/openworlds-atlas-1440x900.png/Volumes/LEXAR/Codex/clawdnd-atlas-surface-smoke/openworlds-atlas-rain-market-1440x900.pngRollback Notes
This PR is viewer-only. It does not change engine/rules/voice APIs or campaign persistence. Reverting it removes
/atlas-surfaceand restores the previous prototype map behavior without touching saved campaign state.Summary by CodeRabbit