Put the tree on the screen
The pager could only step between attempts, and stepping has nothing to say about the thing the tree exists for: taking a path the story moved past and keeping both. Every attempt has been its own node since SP4, so a chip is a node now, and "take this path" forks — or simply switches, when the turn is still the tip and its attempts are leaves nobody has built on. Beside it, a Branches panel: every line the story has taken, with where each left its parent and where it ends, and switch, rename and delete-with-confirm. It sits with Plot/Memory/Scripts/Insights rather than inventing a new place to put a rail. An unnamed branch is drawn from its fork depth, never from its position in the list — a position shifts the moment a branch above it goes. A spatial per-node map was considered and deliberately not built. At the size this has to be verified against it is a second windowing problem, and it can be added later without a new endpoint, since the rail and a map read the same GET /branches. VariantOut grows an id because a fork is addressed by the node being taken, not by an ordinal in a group that renumbers. Driven by hand against the 602-action fixture, which found one bug that no test could: the panel refreshed on actions.length, and a fork swaps a 60-action window for another 60-action window, so it went on drawing a one-branch tree while the story was already on the second. It keys off the counter adoptWindow bumps now. The scroll path was driven at the same time — three prepends of ~16,200 px, the same node holding viewport top 792 to 787, never thrown to the end. That closes the standing gap in this project. Console clean. 396 tests, build clean, no new lint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015H5qiyiR7gtFQaoDphHZ3g
This commit is contained in:
committed by
Parth
co-authored by
Claude Opus 5
parent
cf3d52171e
commit
84827f0f37
@@ -110,6 +110,23 @@ export const api = {
|
||||
method: 'POST', body: JSON.stringify({ index }),
|
||||
}),
|
||||
|
||||
// The story tree (Phase 14). One request draws the whole shape however many
|
||||
// forks there are. The three that change it answer with the story as it now
|
||||
// stands, so the caller replaces its window instead of reloading everything.
|
||||
listBranches: (advId) => request(`/adventures/${advId}/branches`),
|
||||
switchBranch: (advId, branchId) =>
|
||||
request(`/adventures/${advId}/branches/${branchId}/switch`, { method: 'POST' }),
|
||||
renameBranch: (advId, branchId, name) =>
|
||||
request(`/adventures/${advId}/branches/${branchId}`, {
|
||||
method: 'PATCH', body: JSON.stringify({ name }),
|
||||
}),
|
||||
deleteBranch: (advId, branchId) =>
|
||||
request(`/adventures/${advId}/branches/${branchId}`, { method: 'DELETE' }),
|
||||
// Take the story down one attempt. A fork only when it has to be: while the
|
||||
// attempts are still at the tip they are leaves, and the server switches.
|
||||
forkFromAttempt: (advId, actionId) =>
|
||||
request(`/adventures/${advId}/actions/${actionId}/fork`, { method: 'POST' }),
|
||||
|
||||
sendAction: (advId, payload, handlers, signal) =>
|
||||
streamSSE(`/adventures/${advId}/actions`, payload, handlers, signal),
|
||||
retry: (advId, handlers, signal) => streamSSE(`/adventures/${advId}/retry`, {}, handlers, signal),
|
||||
|
||||
Reference in New Issue
Block a user