Hey again. I want to walk through where the canvas has gotten since then, because a lot of the work has been the unglamorous middle of a tool: the parts that don't really sell anything but that you discover you can't ship without. Pause menus. Asset cleanup. Editor performance. We added one big new node type in the last few days too, but most of the actual hours went into the boring half.
Here's roughly where things landed.
The first thing we built was a pause menu. Until now ChoiceStory Studio had one editable surface: the main menu (the launcher surface we walked through in Devlog #1, where the player sees Start / Load / Options / Quit over a configurable background). Adding pause was the first time we had to decide what a sub-surface actually is. We landed on this: the pause menu is not its own node, it's a second authoring face of the main menu, reached through a tab in the editor. Same right panel, same canvas tile, but at runtime it mounts as an overlay over the live scene when the player hits Escape. The design surface borrows the same drag and resize handles the main menu has, so the muscle memory carries over.
Then a feature we didn't plan but turned out to be necessary: asset deduplication. When you import the same video twice, ChoiceStory now fingerprints both files and offers to share the existing entry instead of writing a duplicate.A test project we'd been kicking around had 106 files on disk; after dedup and orphan cleanup it sat at 4 referenced files. The fix had to go deeper than the dedup dialog. Every reference in a project (backgrounds, button images,fonts, the lot) now resolves through a registry that is the single source of truth, so "delete unused files" actually knows what's used and what isn't.
Around the same time we added a performance settings modal in the File menu. Three toggles: follow active node on selection, recompute canvas viewport on resize, node glow animations. Two presets: high-spec PC and low-spec PC. The reason is that our target audience is creators on consumer-grade machines, not workstations, and some of the canvas animations were burning more cycles than the canvas itself. The toggle group is a stopgap; before the alpha we want a real Performance tab. The internal rule that came out of this work: any new feature that adds visible CPU or GPU load gets a toggle on the way in, never as a retrofit.
Next came a side-quest we called the parity pass. The main menu had affordances the pause menu didn't: per-element drag, per-element resize, draggable backgrounds with aspect-locked corner handles. So we pulled the drag and resize pipeline up out of main-menu/ (it never actually held any main-menu-specific knowledge in it) and pointed both surfaces at the same module. Future surfaces (choice overlays, options) inherit those affordances by reusing the same code, which was the whole point of the lift. We also closed a long-standing schema bug while we were in there. If you flipped a background between colour, image, and video schema keeps separate slots per variant and only the active one paints.
The newest addition is the end-screen node. It started life as another sub-surface (same shape as pause) and stayed that way for about ten minutes of planning before we changed our mind. End screens are different. A story can have several of them (good ending, bad ending, secret ending, joke ending) and each one needs its own configuration,so they had to be canvas-creatable nodes you can drop, configure, and connect to. Right-click on the canvas adds one.Right-click on the node copies it; right-click on empty canvas pastes a deep clone at the cursor. The config block for each instance is full: background, title, multi-line outro, music, font, a list of one to five buttons (per-button text, optional image, an appearance delay in milliseconds, and an action: return to main menu, restart, or quit). Optional auto-advance after a configurable delay. The buttons fade in one by one on a timeline the author writes. The runtime swap was the last piece. When a player choice routes to an end-screen node, the playback layer mounts the configured surface instead of trying to play it as a video.
Now the honest part :
A lot of the work above is what made it through. Plenty of stuff didn't. The pause-menu post-closure pass shipped eleven follow-up commits across a single session, and three of them got reverted by commit ten, because every fix had downstream consequences we hadn't mapped. Sub-state in React is the easy half; the hard half is the graph of "if I change this, what else re-renders, in what order, with which stale value." That session ended with a rule we have actually been following since: for every bug fix, write down the side-effect surface before writing the patch, and a list of files you deliberately did not touch. The follow-up count has dropped sharply since.
The CSS side gave us a similar lesson. We spent a first iteration on container queries to scale the pause menu inside variable Player-slot sizes. They worked, mostly, until they didn't on a small slot. We threw it out and used the recipe the main menu already used (viewport-relative clamps + flex with min-height: 0 + overflow: hidden) and it just behaved. The takeaway: if the older pattern already passes every test, the newer pattern needs a reason that survives ten minutes of "but does the existing one already do this?"
What's next is the choice overlay editor, the panel where the buttons that appear over a video (or an image) get designed. Same surface contract, same shared drag and resize infrastructure. We expect it to come together faster than end-screen because most of the substrate is in place now.
If you've read this far, thanks. If you've built something with branching video, or want to, the same line as last time stands. Come tell us what you'd want from a tool like this. Reply here, find us on X as @ChoiceStoryDev, email,whatever's easiest. The harsh stuff especially.
More soon...


Top comments (0)