feat(ui): add story file visualization overlay#211
Conversation
Add a scrollable overlay component for viewing PR story files with prose text and diff-colored code blocks, triggered via `architect story <file>`. - New `story_overlay.zig` component with Markdown/story-diff parsing, keyboard/mouse scroll, texture caching, and open/close animation - Extend notification protocol with story type for socket-based trigger - Add `story` subcommand to the `architect` Python CLI helper - Wire up StoryOverlayComponent in runtime with OpenStory UiAction - Export SDLK_PAGEUP/SDLK_PAGEDOWN in c.zig for page scrolling - Update README, ARCHITECTURE.md, and CLAUDE.md documentation https://claude.ai/code/session_015aTPm6fXdFZszkAxKsT9vL
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fb777e5517
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR adds a new story file visualization feature, allowing users to view formatted PR story files in a scrollable overlay triggered by the command architect story <file>.
Changes:
- Adds
StoryOverlayComponentwith Markdown/diff parsing, scrolling, texture caching, and animations - Extends notification system with story type for socket-based triggering
- Adds
storysubcommand to thearchitectPython CLI helper - Exports SDLK_PAGEUP/SDLK_PAGEDOWN for keyboard navigation
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/ui/types.zig | Adds OpenStoryAction for UI action queue |
| src/ui/mod.zig | Exports new story_overlay module |
| src/ui/components/story_overlay.zig | Implements full story overlay component with parsing and rendering |
| src/shell.zig | Adds "story" subcommand to architect CLI |
| src/session/notify.zig | Extends notification protocol to support story messages |
| src/c.zig | Exports PAGEUP/PAGEDOWN SDL key constants |
| src/app/runtime.zig | Wires up story overlay component and handles story notifications |
| docs/ARCHITECTURE.md | Documents story notification flow and new UI component |
| README.md | Documents new story viewer feature |
| CLAUDE.md | Documents story notification socket format |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Issue: PR review identified four issues in the story overlay: diff lines rendered with a duplicated marker character, an off-by-one loop boundary in prose text splitting, inconsistent bold styling on wrapped headings, and a silent allocation failure when duplicating story paths. Solution: Skip the leading diff marker from the text segment since it is already rendered separately. Tighten the prose-row loop to use strict less-than, preventing a spurious trailing empty line. Propagate the bold flag to all wrapped segments of a heading instead of only the first. Log allocation errors when duplicating the story notification path.
…ualization Issue: The story overlay was a 1300-line file doing parsing, animation, scrolling, layout, and rendering all at once. The diff overlay duplicated most of the animation/scroll/close logic and was missing PAGE UP/DOWN/ HOME/END navigation. The story format also now supports line reference anchors that need visual rendering. Solution: Pulled markdown parsing into a standalone story_parser module with no UI dependencies. Created a shared FullscreenOverlay component that both overlays embed, which removed the duplicate code and gave the diff overlay full keyboard navigation. Anchor parsing handles **[N]** prose markers and <!--ref:N--> code markers, rendered as numbered blue circles with shimmering bezier arrows on hover.
stripProseAnchors copied text into a stack-local buffer, and the resulting slices were stored in DisplayRow.text. After the function returned, every prose line pointed at freed stack memory, producing garbled text and repeated lines in the overlay. Prose lines without anchors now use the original content slice directly. Lines with anchors get heap-allocated copies. Added an owns_text field to DisplayRow so freeDisplayRows knows which text slices to free.
Replaced the filled-circle overlay approach with Unicode circled digits (①②③...) inserted directly into the text. The emojis flow inline with prose and code, so they no longer cover adjacent characters. The parser now inserts the emoji bytes at anchor positions and tracks char_offset as a codepoint count (not byte count) for correct pixel position calculation with multi-byte characters. Code lines with <!--ref:N--> get the emoji appended after a space.
Issue: Circled-number emoji anchors were barely visible, overlapped adjacent text in code diffs, and had misaligned hover areas. Solution: Render anchors as TTF digits inside rounded-rectangle pills that stretch for multi-digit numbers. Insert 3-space placeholders in both prose and code lines so badges sit in their own slot. Fix diff line position math to account for marker_width vs char_width. Add hand cursor and subtle scale-up on hover.
Issue: New modules from the story overlay refactoring were not reflected in the architecture documentation. Solution: Add story_parser.zig to the module boundary table, mention fullscreen_overlay in the components entry, and update gfx/* with the new rendering primitives (fillCircle, fillRoundedRect, renderBezierArrow).
Kept the notification union switch (.status/.story) from this branch and picked up the added `now` parameter to setAttention() from main.
Summary
The story overlay was a 1300-line file doing parsing, animation, scrolling, layout, and rendering. The diff overlay had its own copy of most of that animation/scroll/close logic, and was missing PAGE UP/DOWN/HOME/END.
This PR breaks the story overlay into three pieces, runs both overlays through shared code, and adds anchor visualization:
story_parser.zig-- standalone markdown parser with no SDL/UI dependencies. Handles prose wrapping,story-difffenced blocks, code block metadata, and anchor extraction (**[N]**in prose,<!--ref:N-->in code lines).fullscreen_overlay.zig-- shared overlay component (animation state machine, scroll with all nav keys, close button, scrollbar, layout math). Both story and diff overlays embed this as a field.primitives.zig-- addedfillCircleandrenderBezierArrow(multi-layer diffusion shimmer with arrowhead).story_overlay.zig-- rewritten to use the parser and shared overlay. Anchors render as TTF-rendered digits inside rounded-rectangle pill badges (stretches for numbers >9). Hovering shows a hand cursor, scales the badge up, and draws a shimmering bezier arrow between paired prose/code anchors.diff_overlay.zig-- now embeds FullscreenOverlay. ~230 lines of duplicate code gone. PAGE UP, PAGE DOWN, HOME, END work.~330 fewer lines total, and the diff overlay gets keyboard navigation for free.
Test plan
zig buildpasseszig build testpassesjust lintreports no issues**[N]**/<!--ref:N-->anchors -- pill badges appear inline with proper spacing, hovering shows hand cursor, badge scales up, animated bezier arrow connects paired anchors