Skip to content

Quick Deck v2: the app from the approved designs - #506

Merged
ymote merged 11 commits into
mainfrom
design/quickdeck-v2
Oct 11, 2026
Merged

ymote merged 11 commits into
mainfrom
design/quickdeck-v2

Conversation

@ymote

@ymote ymote commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Quick Deck v2 (os.quickdeck), rebuilt through App Flow from the ten designs the maintainer approved on 11 Oct 2026. This PR is the UI and the design files only. It calls the deck service's open-document methods in apps/quickdeck/design/SERVICE.md. That service is #503, merged into main as 202d7cc, and this branch is rebased on it.

What's here

  • SERVICE.md: contract as built in #503 and SERVICE.md: the guard's final rules (#503): the coordinator's as-built contract and the guard's final rules, each committed alone.
  • Pixel maps (apps/quickdeck/design/map/NN-*.json). One per screen, in PDF Tools' form: every measured run, surface and divider is tied to the region and widget that rebuild it, with geometry, light and dark colours, type size, the review decision and runtime citations. Unmapped: 0 on every screen.
  • The app (bundle/main.splash, manifest 0.2.0, 57 icons):
    • Home: library, engine covers, themes.
    • Editor: navigator with sections; canvas with the engine's render, selection, handles and text edited in place.
    • Inspector: Format, Layout, Theme, Notes; charts with a data grid; tables.
    • Sorter with sections; New from an outline (typed, or Draft with AI through model.complete); Present on a dark stage; Export (.pptx, PDF, pictures).
    • Every state in the brief, light and dark.
    • The manifest declares storage, files, deck, model (all in App Hub's KNOWN_CAPABILITIES at the pin) and asks for a 1536 x 1024 window (schema_minor 1).
  • Tests:
    • crates/shell/src/quickdeck_model_tests.rs: the pure functions in a script VM.
    • tests/ui.py: card-host runs on the dev fixture; the real-engine journey in a hidden shell, now also on Linux on a private headless weston, as PDF Tools does.
    • dev-fixture/: a stand-in that answers the way deck service v2: open documents for Quick Deck v2 #503 does.
  • Docs and evidence: apps/quickdeck/README.md (English and Chinese), apps/README*.md, and apps/quickdeck/tests/evidence/v2-20261011/ (frames, side-by-sides, receipt.json).

How it was tested

  • Model tests, on the Linux build host, on the rebased tree. cargo test --locked -p octosense-shell --lib quickdeck_model: 22 pass. With --features app-hub: 23 pass; the extra one is the manifest's window hint.
  • App Hub card-host (macOS, Apple silicon, 64 ms budget). missing, fixture and states pass, light and dark, with no script errors. This card-host ignores MAKEPAD_SPLASH_BUDGET_MS. An earlier round passed every step, but its log had one budget overrun right after a PNG decode, at load averages of 36 to 100. The rebase changed no file of the app, its fixture or its tests (same digests), so these frames stand.
  • Real engine, in a hidden desktop shell on Linux (headless weston, at the 64 ms budget):
    • The shell was built from this branch rebased on main 202d7cc, so it runs the merged service with the guard's final rules. Earlier rounds ran on a local merge with the service's branch at 74be4c0, never pushed.
    • shell passes, light then dark through the shell's style menu, and so does restart. No script errors and no overruns. Nothing changed for the app with the final guard.
    • The journey: Home; Draft with AI answering no_provider in the app's words; a deck from a typed outline; text edited in place; bold; a chart with its grid; undo and redo; a layout; a theme; notes; sorter duplicate, hide and section; save; .pptx and PDF exports; Present; then a restart.
    • The shell opens Quick Deck at 1296 x 698, an app area of 1292 x 662.
  • Earlier failed rounds and their fixes are kept in receipt.json. Ten shell rounds found five app bugs, all fixed:
    • deck.hit refuses an empty selected list.
    • The chart strip didn't wrap in a narrow canvas.
    • The outline's Make deck went below the fold in a short window.
    • A note stayed on the Present stage.
    • An images export sent include_hidden, which the service refuses.

Maps: one line per screen

  • 01-home. Theme previews are drawn from deck.themes colours (no theme fonts). Covers are deck.cover. Duplicate and Remove are quiet icons on each card, from the brief's job 9.
  • 02-edit-text.
    • The edited box is a TextInput over a deck.view {editing} render. It shows plain lines without bullets.
    • Formatting applies to the whole box or to the paragraphs chosen in "Applies to", because TextInput has no selection.
    • Box's toggles start off: format_state has no anchor or autofit.
  • 03-chart.
    • A new chart carries the engine's sample data (Q1–Q4, three series), which the app sends.
    • The design's five palettes become two, because the engine draws only colourful and monochrome.
    • The design's "Region" header is sample text.
  • 04-layout. A slide's layout is matched by id. The duration comes from deck.slide in milliseconds. Transitions don't play.
  • 05-theme. The engine has 13 colour schemes, so they sit three to a row. The five not named after a theme show their name only (contract change 1). The current colours and fonts are inferred from the theme.
  • 06-sorter. The drag marker and the floating tile aren't drawn: redrawing the grid would end the drag. The strip says where the tile would go.
  • 07-outline. Real theme names replace the invented four. Points fields grow with their lines. The counts and Make deck stay pinned in view.
  • 08-present. The stage sits inside the app's window. Each build step shows its end state. Notes come from deck.slide when the preview was cut.
  • 09-export. The "3 per page" drop-down becomes chips (1–9) shown with Handouts.
  • 10-dark-notes. The full notes come from deck.slide, with "Reading the notes…" until they arrive. The navigator opens a window around the current slide, with a "‹ Slides 1–n" link.

Remaining differences against the designs, and why

  • The chrome keeps PDF Tools' shared heights (tabs 53, toolbar 54, status 44); the images use 44–78.
  • The runtime's UI font is wider than the designs' (about 8.2 vs 6.6 pt per character), so with six decks open the tab titles are cut.
  • In card-host, sample art is the fixture's drawings, and photos are plain blocks.
  • The theme panel and Export scroll in the shell's smaller window.
  • In card-host, theme.font_bold draws regular; in the shell it is bold.
  • Only screen 10 has a dark design. The other screens' dark versions come from the shared tokens.

Runtime gaps (makepad d653bc44)

  • No key events reach a script. widgets/src/text_input.rs:3362, 3697: KeyDownUnhandled is a widget action. Only on_change and on_return reach scripts (:675-677). So every shortcut is a button.
  • No TextInput selection. text_input.rs:2400-2425: script_call answers text and set_text only.
  • Rendering a region rebuilds its widgets. widgets/src/view.rs:248-258. A drag held by one of them ends, and a field in it loses its typing. So drags draw in their own layer, and edits and notes never redraw their field.
  • Scripts can't read or set a scroll position. A view keeps its own (view.rs:296-306). So the navigator and sorter show windows of slides.
  • The regex has no \x escapes. libs/regex/src/parse.rs:354-366. The script uses [:cntrl:] instead.
  • PNG decoding counts against the 64 ms handler budget. The budget is enforced at platform/script/src/vm.rs:1232. card-host's runtime lacks the MAKEPAD_SPLASH_BUDGET_MS patch.
  • Script language quirks.
    • A computed key on a literal object isn't its named field.
    • pick() evaluates both arguments.
    • loop can't be an object key.
    • widget_async.rs:1574 logs harmless "script_result dropped" warnings for nested regions.
  • OctoSense bundles no theme fonts (SERVICE.md decision 7). No app can make the OS window full screen.

Contract changes the design needs (not made here)

(deck.hit with selected: [], which I listed before, is settled: the final guard treats it as no selection, and the app leaves an empty list out anyway.)

  1. deck.themes: color_schemes as [{name, colors}] with the 12 slots. The engine lists names only (engine/src/cmd/design.rs:92).
  2. deck.open / deck.state: the deck's current colour-scheme and font-scheme names.
  3. deck.open: footer state (slide numbers, date, footer text).
  4. deck.format_state: anchor and autofit.
  5. deck.slide: a chart's legend, data_labels, gridlines and palette, and a table's options (header and total rows, banding, first and last column). slide.inspect omits them (engine/src/cmd/inspect.rs).

Not verified

  • A real import from the device: macOS refuses the dialog for a hidden window, and the Linux host has no dialog helper. So the import guard's refusals through the app are unverified too.
  • Draft with AI with a real provider.
  • A hidden shell on macOS.
  • With the real engine: pictures, tables, the shape gallery, backgrounds, long notes in Present, and an images export.
  • Windows under 1180 points; other screen sizes; phones.

🤖 Generated with Claude Code

ymote and others added 11 commits October 11, 2026 13:47
App Flow's first two steps for a desktop deck editor over the deck
engine, in the same family as PDF Tools v2. No images are generated:
that paid step waits for the maintainer's approval.

- design/BRIEF.md: jobs, the window layout (tabs, toolbar, slide
  navigator, canvas, a Format / Layout / Theme / Notes inspector, status
  line), ten screens and their states, every action mapped to the
  deckcraft commands it runs with their safety classes, what the deck
  service lacks today, the engine limits the design accepts, data and
  open questions.
- design/source/prompts.md: the shared style block and ten screen
  blocks (nine light, one dark) at 1536 x 1024, structured like PDF
  Tools' prompts so the same generation script parses it.
- design/SERVICE-DRAFT.md: a draft of the app-facing deck service
  contract (open documents per caller with undo, typed editing methods,
  renders in a managed cache, present steps, export options, error codes
  and caps), each method mapped to engine commands, for the coordinator
  to settle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ten screens generated with the OpenAI Image API (gpt-image-2, 1536 x 1024,
quality high) from source/prompts.md, authorized by the maintainer on
11 Oct 2026. Each screen keeps its exact prompt text (NN-*.prompt.txt),
its untouched PNG and its measurement (NN-*.measured.json, from
measure_desktop.py, a copy of PDF Tools' desktop adaptation of App
Flow's observe and measure steps, with App Flow's ocr.swift).
generation.json records the provider, model, sizes, hashes and usage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SERVICE-DRAFT.md becomes SERVICE.md with the coordinator's decisions on
its eight open questions (op-grouped API, a per-method command count,
undo through the engine's public History, the service's own import
guard before the engine sees a byte, deckcraft-anim for present, PDF
Tools' cache numbers, no font bundling, the pdf service's test
standard), plus Draft with AI through model.complete and a 1536 x 1024
window hint. The maintainer approved the ten designs on 11 Oct 2026.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drops the draft header, and brings the body in line with the settled
decisions: the gate admits every command with each method's own count,
the import guard runs on every path that opens a file and names its
codes, a cells fill holds at most 1,024 cells, and deckcraft-anim is a
dependency. Settles BRIEF.md's five open questions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One map per approved screen in apps/quickdeck/design/map/, in PDF Tools'
form: every measured text run, surface and divider tied to the region and
widget that rebuild it, with its geometry, light and dark colours (dark from
10-dark-notes), type size from the ink heights, the review decision that
applies, the runtime source it relies on, and what the runtime or the
service can't do yet. Sample art inside slides, thumbnails, tiles, covers,
layout pictures and theme previews is the engine's render (deck.view,
deck.layouts, deck.cover, deck.themes), not rebuilt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A presentation editor rebuilt from the ten approved designs through App
Flow, on the deck service's open documents (design/SERVICE.md, as built in
#503): a library with the engine's covers; tabs; a toolbar with insert
strips; a navigator with sections; a canvas with the engine's render,
selection, handles and text edited in place; an inspector with Format,
Layout, Theme and Notes; a sorter with sections; New from an outline, typed
or drafted with the person's own provider (model.complete); Present on a
dark stage inside the window; Export to .pptx, PDF and pictures; and every
state the brief lists. Light and dark through shared tokens; state on
mod.quickdeck_state; no fixture or replay path in the bundle.

The manifest declares storage, files, deck and model, asks for the
designs' 1536 x 1024 window (schema_minor 1) and moves to 0.2.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dev-fixture/engine.splash is a stand-in for the deck service that answers
SERVICE.md's methods as #503 does (layouts by id, a notes preview in
deck.slides, transitions in milliseconds, colour schemes by name);
make_fixture.py fills the app's storage with the designs' sample decks and
the engine's real catalogs. v1's fixture goes.

tests/ui.py runs every designed screen and state in card-host, light and
dark, beside its design, and the real engine's journey in a hidden desktop
shell (on Linux on a private headless weston, as PDF Tools' ui.py does),
then a restart. quickdeck_model_tests.rs runs the bundle's pure functions
in a script VM.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
apps/quickdeck/README.md (and its Chinese) describes v2: the window, the
screens and the engine methods behind them, opening a presentation from the
device, storage, the runtime's limits the script works around, the tests
and what is verified. tests/evidence/v2-20261011 holds the card-host
side-by-sides and states, light and dark, the real engine's frames from a
hidden Linux shell, and a receipt with digests, commands, the failed rounds
before these, and what wasn't verified. apps/README.md and its Chinese
follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The branch is rebased on main 202d7cc, which has the deck service. The
shell runs (light, dark, restart) passed again with a shell built from
that tree, with no script error or overrun; nothing changed for the app.
The Linux frames and the receipt now name that head and the merged service
instead of the earlier local merge with the service's branch. The card-host
frames stand: the rebase changed no file of the app, its fixture or its
tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ymote
ymote force-pushed the design/quickdeck-v2 branch from 8eb2ad5 to ee8d2e8 Compare October 11, 2026 20:59
@ymote
ymote marked this pull request as ready for review October 11, 2026 21:00
@ymote

ymote commented Oct 11, 2026

Copy link
Copy Markdown
Contributor Author

Local CI passed on ee8d2e8 (tools/ci-local.sh --only all --linux-host --offload, 14m34s, Darwin arm64; the ubuntu jobs and the macOS jobs' portable steps (their macOS steps ran here) on the Linux build host, Linux x86_64).

GitHub would run for this PR: desktop.yml, phone.yml, apps.yml. Merged on this local pass (macOS runner queue); GitHub CI runs on the merge commit on main.

Job Step Result Time
ci-local / drift The local mapping fits the workflows PASS -
desktop.yml / desktop Prepare the pinned framework sources PASS 1s
desktop.yml / desktop Compile the desktop with the shared runtime PASS 4m08s
desktop.yml / desktop Desktop tools and scripts PASS 14s
desktop.yml / desktop (linux) Prepare the pinned framework sources PASS 0s
desktop.yml / desktop (linux) One copy of every shell source PASS -
desktop.yml / desktop (linux) In-app updater and installer handoff PASS 1m38s
desktop.yml / desktop (linux) One Makepad, App Hub, octos and Rinx in the locked graph PASS 2s
desktop.yml / desktop (linux) The native apps' generated places match native-apps.json PASS 0s
desktop.yml / native-host-api Prepare the pinned framework sources PASS 1s
desktop.yml / native-host-api Build the native acceptance host and pinned Hub CLI PASS 36s
desktop.yml / native-host-api Signed app tool calls a real OS permission API PASS 3s
phone.yml / home Prepare pinned sources and the reviewed runtime patch PASS 1s
phone.yml / home Validate launcher icons and Apple asset catalogs PASS 3s
phone.yml / home Compile Home and its bundled modules PASS 2m57s
phone.yml / home (linux) Prepare pinned sources and the reviewed runtime patch PASS 0s
phone.yml / home (linux) Verify the single runtime graph PASS 2s
phone.yml / home (linux) The native apps' generated places match native-apps.json PASS 0s
phone.yml / home (linux) The pinned octos revision PASS 0s
phone.yml / home (linux) Build octos (unless cached) PASS -
phone.yml / home (linux) Build Home, App Hub admission and runtime policy tests PASS 3m21s
phone.yml / home (linux) Test Home, App Hub admission and runtime policy PASS 42s
phone.yml / home (linux) Two-lane scenario (real kernel, scripted model) PASS 26s
phone.yml / home (linux) Build opt-in AppCard tests PASS 2m41s
phone.yml / home (linux) Test opt-in AppCard PASS 1s
phone.yml / home (linux) Build craft-engine relay and system-chat tests PASS 2m56s
phone.yml / home (linux) Test craft-engine relay and system chat PASS 4s
phone.yml / home (linux) Build linked Terminal tests PASS 2m31s
phone.yml / home (linux) Test linked Terminal PASS 1s
phone.yml / home (linux) Build Wasm and runtime policy tests PASS 1m18s
phone.yml / home (linux) Test Wasm and runtime policy PASS 11s
apps.yml / services (linux) python3 tools/setup.py PASS 0s
apps.yml / services (linux) Shared system app interface PASS 0s
apps.yml / services (linux) Kernel service PASS 19s
apps.yml / services (linux) OctoSense release updater PASS 6s
apps.yml / services (linux) App peers PASS 29s
apps.yml / services (linux) AI providers config PASS 6s
apps.yml / services (linux) Connected provider protocols and Linux host adapter PASS 46s
apps.yml / services (linux) L0 in-card chat (sys.chat, host side) PASS 10s
apps.yml / services (linux) System toolbox (workflow templates) PASS 1m29s
apps.yml / kernel-security (linux) python3 tools/setup.py PASS 0s
apps.yml / kernel-security (linux) The pinned octos revision PASS 0s
apps.yml / kernel-security (linux) Build octos (unless cached) PASS -
apps.yml / kernel-security (linux) Real-kernel tests PASS 41s
apps.yml / apps (linux) python3 tools/setup.py PASS 0s
apps.yml / apps (linux) Host services (Mail, AI providers, News) PASS 2m08s
apps.yml / apps (linux) Connected accounts and Rinx editor PASS 1m32s
apps.yml / apps (linux) Shell AI services (crates/ai-host) PASS 2m59s
apps.yml / apps (linux) AppCard runtime setup safeguards PASS 0s
apps.yml / apps (linux) AppCard clippy (own crates; shared runtime compiles) PASS 27s
apps.yml / apps (linux) AppCard transport and store PASS 7s
apps.yml / apps (linux) One Makepad, App Hub, octos and Rinx in the locked graph PASS 3s
rom.yml / product (linux) python3 -m unittest discover -s tests -v SKIPPED (!) -
rom.yml / product (linux) Check generated Agent Binder client SKIPPED (!) -
rom.yml / product (linux) bash -n scripts/stage-forks.sh scripts/publish-release.sh scripts/apply-to-tree.sh scripts/build-rom.sh PASS -
rom.yml / web-installer (linux) npm ci --ignore-scripts --no-audit --no-fund SKIPPED (!) -
rom.yml / web-installer (linux) npm test SKIPPED (!) -
rom.yml / web-installer (linux) npx playwright install --with-deps chromium SKIPPED (!) -
rom.yml / web-installer (linux) npm run test:browser SKIPPED (!) -
rom.yml / web-installer (linux) python3 -m unittest discover -s tests -p test_installer_manifest.py -v SKIPPED (!) -
rom.yml / web-installer (linux) bash -n scripts/release.sh SKIPPED (!) -
linux-host / sandbox (linux) python3 tools/setup.py PASS 0s
linux-host / sandbox (linux) Process sandbox on Linux (Landlock, seccomp) PASS 1m45s

Skipped (these did NOT pass; (!) marks a skip that blocks tools/ci-local-merge.sh):

  • rom.yml / product (linux): python3 -m unittest discover -s tests -v: javac -version does not work here: install a JDK (17 or newer) and put its bin/ on PATH or set JAVA_HOME
  • rom.yml / product (linux): Check generated Agent Binder client: needs build-tools/35.0.0/aidl, platforms/android-35/framework.aidl in the Android SDK (no Android SDK found): install the SDK packages 'build-tools;35.0.0' and 'platforms;android-35' (sdkmanager) and set ANDROID_HOME
  • rom.yml / web-installer (linux): npm ci --ignore-scripts --no-audit --no-fund: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): npm test: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): npx playwright install --with-deps chromium: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): npm run test:browser: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): python3 -m unittest discover -s tests -p test_installer_manifest.py -v: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): bash -n scripts/release.sh: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH

Notes:

  • GitHub runs Python 3.12; this run used Python 3.9.6
  • GitHub runs Python 3.12; the Linux host used Python 3.14.4

@ymote
ymote merged commit aead68f into main Oct 11, 2026
1 of 6 checks passed
@ymote
ymote deleted the design/quickdeck-v2 branch October 11, 2026 21:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant