Repository navigation
app: a demo gives back a folder opened from a zip's bytes - #596
Merged
Merged
Conversation
A demo sets the person's session aside and reopens it when it ends, by path. A document whose path cannot open it again was lost: a file the web page fetched or the person uploaded, and a zip opened as the project folder, whose tab is its mount. That is fizzyed.it's `?open=/site.zip`: after the tour, the site was gone. Now `begin` keeps the bytes of each document its path cannot reopen (`Plugin.documentBytes`), and `end` opens those first, so a zip mounts again before the folder and the files inside it are opened. The bundled-demos test opens a zip from its bytes first and checks it is mounted and the project folder again once every demo has played; the test build bundles the archive plugin for it. Part of fizzyedit/plans#30 (step 0). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
force-pushed
the
app/demo-keeps-bytes
branch
from
October 18, 2026 23:39
a978337 to
75ed63e
Compare
foxnne
marked this pull request as ready for review
October 18, 2026 23:39
foxnne
enabled auto-merge (squash)
October 19, 2026 01:07
2 of 8 tasks
foxnne
added a commit
that referenced
this pull request
Oct 19, 2026
…em (#608) Part of fizzyedit/plans#30 (step 1: a demo registry). ## What changes A plugin can ship demos, and anything can list and play the demos the app has. This is the seam the `guides` plugin (step 2) is built on, and that pixi's own guides come in through later. - **`host.registerDemo(.{ .name, .title, .tape })`**, called in `register`. The tape is ZON or binary bytes built with the SDK's `tape` module. The host copies the name, title and tape, so nothing points into the plugin's image, and drops them when the plugin unregisters. A name already registered is refused (`error.DemoExists`). `Host.demos_generation` moves whenever the list changes. - **The `demos` service (`sdk.services.demos`)**, provided by fizzy in `src/editor/Demos.zig`: - `list` returns every demo fizzy can play, its own first, each with its length, chapters and origin (`bundled`, `plugin`, or `hosted` for step 3). - `play(name, at_ms)` plays one, from a chapter's start if asked. It returns `unknown`, `busy` (a live tape is driving) or `unsaved` (the same refusals a demo already had, now with a reason). - `current` names the demo playing. A tape loaded some other way since isn't mistaken for it. - `generation` is cheap to ask every frame. - **The list is built lazily**, and again only when the host's demos change. A plugin's tape is loaded the way a demo is played. One that wouldn't play is left out with a warning instead of being listed and then refused: a live tape, a step no loaded plugin applies, or a name fizzy already has. - **`fizzy.demo.play` ("Demo: Play by Name…")** plays any listed demo by `name`, from `at`. The bundled demos keep their own palette rows. A plugin's demo gets none, because a `Command` carries only its owner's state, so one row per runtime demo would need a context it doesn't have. The guides view (step 2) is where those are browsed. - `Demo.startable` says why a demo can't start, and `Demo.loadDemoTape` is the demo check `playTape` already used. Changed from the plan: the plan had the `automation` service growing `demos()` and `playDemo()`. `automation` is about live tapes on whatever is open. A demo is fizzy's player setting the session aside, so it got a service of its own, and `automation`'s version is untouched. ## SDK impact - [ ] None - [ ] Core-only or additive: reaches plugins at the next SDK release - [x] Fingerprint moved: recorded in `sdk/src/version.zig`, `sdk_version` untouched, PR labelled `sdk` - [ ] SDK release: bumps `sdk_version`, lists the `sdk` PRs since the last `sdk-v*` tag For plugin authors: `sdk.Demo` and `Host.registerDemo` are new; `sdk.services.demos` is a new service at version 1. Nothing existing changed shape. ## Verified - [x] macOS: - `zig build test`: a new `Host` test checks that `registerDemo` keeps its own copy (the caller's buffers are overwritten after it returns), refuses a name twice, and drops a plugin's demos at `unregisterPlugin`, with the generation moving each time. - `zig build test-integration` (81/81 steps, after merging `main` with #596 in): the demo test lists the bundled demos through the service, then registers three demos. A plugin demo is listed with two chapters; one reusing the name `tour` and a live tape are left out, with exactly those two warnings. The plugin demo plays by name to its end, named by `current`. Started at its second chapter, it's at that chapter. A tape loaded another way isn't `current`, and nothing is once unloaded. - `zig build`, `zig build check-web`, `zig build test-sdk-version`, `zig build check-tests-reached`, `scripts/check-fmt.sh`. - [ ] Windows: - [ ] Linux: - [ ] Web: compiles (`check-web`); not run in a browser. ## Follow-ups - Step 2, the `guides` plugin, lists the service and plays what's clicked. - Step 3: `hosted` returns `unknown` until the web's `demos/index.json` is read into the list. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 19, 2026
foxnne
added a commit
that referenced
this pull request
Oct 19, 2026
Part of fizzyedit/plans#30. The new tour drops a tab on the editor's edge, and found this. ## What changes A demo sets the person's session aside (folder, documents, settings) and gives it back at the end, but it never set aside the document panes those documents sat in. A demo that split the editor, for example by dropping a tab on its edge, did three things wrong: - it left its pane behind after it ended; - it wrote its arrangement over the person's `panes.zon` while it played, because the workbench saves whenever the tree changes; - a seek back to a keyframe replayed onto the panes a later moment had made, so play and replay disagreed. Now: - **`Workbench.holdPanes`** (at `Demo.begin`) keeps the person's arrangement in memory and the pane they were in. While it's held, nothing is saved. - **`Workbench.onePane`** (at every keyframe) cuts to one pane. The others leave with their leaves (`rebuildWorkspaces`). A keyframe declares the window outright, and now it does the same for panes. - **`Workbench.restorePanes`** (at `Demo.end`, before the person's documents reopen) puts their arrangement back, and saving with it. The hold is a copy of its own, made through `snapshot` and then `fromSnapshot`. A snapshot borrows the pane names from the live tree "until it next changes", and the first cut replaces that tree. The first version held the snapshot itself, and the names it restored were freed memory: `Failed to rebuild workspaces`, which now says which error (`NoSuchPane`). ## SDK impact - [x] None ## Verified - [x] macOS, `zig build test-integration` (81/81 steps): the demo test plays a tape that drags a tab onto the editor's right edge. It checks two panes at the end, one pane after a seek to the keyframe, the person's own pane count once unloaded, and nothing left held. #596's zip check still passes after all the demos, and so does the headless tour test. - [x] `zig build`, `zig build test`, `zig build check-web`, `zig build check-tests-reached`, `scripts/check-fmt.sh`. - [ ] Windows: - [ ] Linux: - [ ] Web: the same code path, minus `panes.zon`, which the web never writes. ## Follow-ups - Which pane each of the person's documents was in still isn't kept: they reopen into the pane they were in last, as before this change. Fixing that belongs with the workspaces plan's "documents through the app" step (`plans/WORKSPACES_PLAN.md`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
added a commit
that referenced
this pull request
Oct 19, 2026
…ry (#629) Part of fizzyedit/plans#30. **Merge after #621 and #626**: this branch is built on both and on `main` (which has #623 and #624), and until they land its diff shows their commits too. Its own change is `src/editor/demos/tour.zig`, `catalog.zig` and `docs/AUTOMATION.md`. ## What changes The tour was the explorer, typing, the palette and a markdown preview, with long holds (8.5 s on the first card). It now covers what a person needs to get around, and what fizzy's windowing does, in 58 seconds: | Chapter | At | What it shows | |---|---|---| | Welcome | 0:00 | a short title card, no hold | | Tabs | 0:03 | a tab dragged into order, another dropped on the editor's edge: a pane beside | | Places | 0:10 | a place's corner button, its picker, and Split | | Floats | 0:18 | the Files view dropped on its own place's middle: a float, carried by its header over the code | | Materials | 0:25 | Liquid Glass, frost, blur, clear and opaque under that float (`fizzy.windowMaterial`, #621), then closing the float sends the view home | | Plugins | 0:38 | the store: everything seen so far is a plugin | | History | 0:42 | typing, the grip at the page's foot filling toward the history's cap (#624), and the bar it opens | | Your turn | 0:54 | where to find it again: Guides on the rail | Each chapter that rearranges the window opens on a keyframe. A snapshot holds documents and settings but not the layout, so a seek or a jump from the guides view lands on a cut rather than on a window still arranged the later way. The catalog names the anchors the tour aims at (`place`, `corner`, `cornerButton`, `historyGrip`, `historyLine`). `docs/AUTOMATION.md` lists the ones its table lacked: `history.grip:`, `history.export:`, `history.collapse:`, `float-header:`, `float-close:` and `picker.empty`. The history chapter shows the bar and how to scrub it, but doesn't scrub. A snapshot puts a document's text back but not its history, so a seek replaying a scrub lands on other text. What making it found, each its own PR: - #621: the window's material had no setting. - #623: a demo left its panes behind, and wrote them over the person's `panes.zon`. - #626: the player checked the previous chapter's snapshot on a rewind. - #624: the grip's fill now measures the history cap, per review. ## SDK impact - [x] None of its own. #621 and #623 have none either; #626 changes no shape. ## Verified - [x] Web, in the browser pane: played start to finish on `?demo=tour`. Every chapter landed: the drags, picker, float, material switches, store and history bar. - [x] macOS, `zig build test-integration` (81/81 steps): - `tests/demos.zig` plays the tour to its end with no timeouts and seeks to random moments and every chapter, landing on what playing reached with no mismatches; - the headless tour test passes, as do #623's panes check and #596's zip check after it. - [x] `zig build`, `zig build check-web`, `zig build check-tests-reached`, `scripts/check-fmt.sh`. - [ ] Windows: - [ ] Linux: ## Follow-ups - A pause before the tour clicks the history grip broke seeks there (the line never drew on replay). Something in the grip's rest timing doesn't follow demo time. The tour clicks it without the pause. - On the web, the float's view covers most of its glass, so the material change shows mainly in its header and edges. A sparser view floated would show it better. - Hosted guides (step 3) and `?view=guides` (step 4) are next. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
3 of 5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of fizzyedit/plans#30 (step 0: check that a guide played over the site gives the site back).
What changes
A demo sets the person's session aside and reopens it by path when it ends (
Demo.begin/end). A document whose path can't open it again was lost:The second case is fizzyed.it's
?open=/site.zip. The keyframe closes the zip's tab, which unmounts it, and after the tour the site was gone.Now
beginkeeps the bytes of each document whose path can't reopen it, usingPlugin.documentBytes, the same encode a save does. "Can't reopen" means the path is neither on a mount nor on disk, and on the web, not on a mount.endopens those documents from their bytes first, so a zip mounts again under the same prefix before the project folder and the files inside it are opened.The document that was active is active again, whichever way it came back. A never-saved document (
untitled-1, clean, since a demo won't start over unsaved work) is left out, as before. Reopened from its bytes, it would come back as a file nameduntitled-1.Tried and dropped: keeping the person's documents open through the demo, with the demo closing only its own. The workbench's panes would still hold the person's tabs during the demo, and taking those out is workspaces work (
plans/WORKSPACES_PLAN.md).SDK impact
Verified
tests/demos.zig) now opens a zip from its bytes before playing every demo, then checks the zip is mounted and is the project folder again, with the same number of documents open andsite.zipstill the active one. It failed before this change: the project folder was not the zip's. The test build now bundles the archive plugin for it.zig build test-integration81/81 steps,zig build,zig build test,zig build check-web,zig build check-tests-reached.reopenableis false for anything off a mount); not run in a browser.scripts/check-fmt.shflagsbackend/src/platform/win32_titlebar.zig, which has been unformatted onmainsince #463 and isn't in this diff; #597 formats it.Follow-ups
guidesplugin, hosted guides,?view=.🤖 Generated with Claude Code