Release planning

CadCraft 1.0 impact map

Every fix and feature lined up for 1.0, and what each one touches: which apps, and which layers of the stack.

ProjectCadCraft
Sheet0.10 impact
Items110
Date2026-11-09
51Fix
22Feature
0Spike
28Platform
0Site ops
8Sanity check
1Decision
≈ 319days in the written 0.10 plans
  • Planned 101 on the plan for the release it is filed under
  • Built 0 built and working in /lab (the dev builds). Whether the public has it is its reach: "in the lab", "Live" (the last gate) or "switched off"; see docs/REACH-LIVE.md
  • Partly built 1 part of it is built in /lab; the rest waits (see "Waits on")
  • Promised 0 the live site already says it is coming
  • Moved 0 moved here from an earlier release or wishlist
  • Found 0 bug found after a release shipped; fixed in a point release or the next one
  • Candidate 3 recommended in a spike or session log; owner to choose
  • Community please test 0 built and in /use; a Discord post gives the steps and the expected result and asks people to try it on their own devices, files or know-how
  • Decision Time 5 a decision, check, file, key, flag or go only you can give; folds into the list once answered

Built means built and working in the lab. Live means the public can use it, and is the last gate: 0 Built · Live, 0 Built · in the lab.

Sheet 1 · impact areas

Where 0.10 lands

How many items touch each app and each layer, by kind. One item can touch several areas, so the rows add up to more than the item count. Pick a row to filter the schedule below.

Impact areaFixFeatureSpikePlatformSite opsSanity checkDecisionAll
Apps
CadCraft 20 17 – 10 – 3 1 51
BimCraft 18 20 – 9 – 4 1 52
ModelCraft 19 20 – 10 – 3 1 53
MarkupCraft 12 16 – 9 – 3 1 41
TakeoffCraft 14 16 – 9 – 3 1 43
CivilCraft 21 18 – 10 – 4 1 54
DetailCraft 15 17 – 9 – 4 1 46
PartCraft 15 17 – 9 – 3 1 45
Studio – 1 – – – – – 1
SuperCad Studio – 6 – 6 – 1 1 14
Layers
Site and services 13 3 – 8 – 1 – 25
Desktop host – 1 – 1 – – – 2
App shell 5 15 – 8 – 2 1 31
App code 23 4 – 3 – – – 30
Our engines 8 – – 1 – 1 – 10
Vendor engines – – – – – – – 0
Drawing surface 3 – – – – – – 3
Help and words 2 1 – – – 1 – 4
Tests and tooling 2 1 – 2 – 3 – 8

Sheet 2 · schedule

Every fix and feature

Grouped by track. App chips carry each app’s layer colour; Studio is in ink. "Waits on" names what has to happen first; the small lines under it say who asked and where the item is written up.

Add an item Fork map (Rust and C++ forks) The roadmap

Issues sync every 10 minutes; last sync Nov 9, 2026 7:00 pm.

ItemWhatAppsLayersStatusDaysWaits onIssues
Performance roadmap — wave 1 6
PlatformPERF.2 Link to PERF.2Comment on PERF.2 Apps: the 532 KB language catalog inlined in every app page (65 % of the HTML, never cached) as a cached static file per build and locale

Measured 2026-11-08: /use/cadcraft is 828 KB of HTML (205 KB gzipped) and 532 KB of it is <script id="cc-lang"> (8,818 strings; cmd 83 KB, shell 82 KB, frame 32 KB, m3d 28 KB...), regenerated and sent on every page view because the page itself is dynamic. Readers: assets/js/app-shell.js, app-boot.js, app-lang-boot.js, i18n.js (one copy per app), supercadcraft.js, super-tools.js, exact-client.js; all read #cc-lang synchronously. Plan: Lang::bootTag writes a small tag and the catalog moves to a classic script /assets/apps/<slug>/<version>/lang/<locale>.boot.js?v= (or a generated file under a cache folder for the shell part) that sets window.ccLangCatalog, loaded with the week-long asset cache; the readers take window.ccLangCatalog first, #cc-lang second (so frozen releases and the browser edition keep working). Second visit: 0 bytes for strings instead of about 100 KB gzipped. Releases are frozen so the file can be written at release time (bin/release-app.php); a Discord member builds generate it on demand keyed by the lab stamp. Keep Lang::use (PHP needs the shell strings for the bar and Settings).

– Planned – –
PlatformPERF.3 Link to PERF.3Comment on PERF.3 Apps: the "Save for offline" file list (128 KB inline, 2,054 files stat-ed per page, 42 ms) fetched on demand instead

Measured 2026-11-08: every app page carries <script id="cc-offline"> (128 KB: the URL of every file the service worker would save) and PHP spends 14 ms in AppBuilds::offlineFiles plus 28 ms in tools/shell/offline-size.php (a filesize of all 2,054 files) to build it. It is read only when a person clicks Save for offline (assets/js/app-offline.js) and by help-panel.js for the listed-files check. Plan: keep key/page/bytes in the tag; move urls to a small endpoint (or a static JSON per release written by bin/release-app.php, a Discord member builds on demand) fetched when the button is pressed; cache offline_size per release (frozen) and per lab stamp for a Discord member. Saves about 15 KB gzipped per page view and 42 ms of PHP.

– Planned – –
PlatformPERF.4 Link to PERF.4Comment on PERF.4 Apps: modulepreload hints for the static import closure, so the import waterfall is one round trip deep instead of 4 to 8

Measured 2026-11-08 (static import graph from each release's entry module): cadcraft 281 modules, depth 6 (99 at depth 1, 104, 51, 21, 4, 1), 4.6 MB; bimcraft 422 modules, depth 4, 6.5 MB; partcraft 269 modules, depth 8; markupcraft 78 modules, depth 3. The browser only discovers level n+1 after level n arrives, so each level costs a round trip even with HTTP/2 (PERF.1). Plan: AppBuilds::headTags adds <link rel="modulepreload" href=...> for the entry's static closure (regex over import/export-from lines, cached per release in storage/ and per lab stamp for a Discord member builds; about 25 KB of tags for cadcraft, gzips well). Dynamic import() sites (38 in cadcraft, 97 in bimcraft) stay lazy. Measure with tools/perf/startup.mjs before and after; most valuable after PERF.1, still a win on HTTP/1.1 for the small deep levels.

– Planned – –
Performance roadmap — wave 2 12
PlatformPERF.10 Link to PERF.10Comment on PERF.10 Memory ceilings: 850 MB for an 8 MB DWG, 1.5 GB for a 47 MB IFC in Node; 867 to 932 MB heap peaks in the browser — a budget per format, measured in the suite

Measured 2026-11-08: Node RSS after read + write of Plans.dwg (8.2 MB) 854 MB; after open + geometry + save of IFC Schependomlaan (47 MB) 1.47 GB, the 22.5 MB showcase 1.18 GB; browser JS heap peaks: ModelCraft glTF 932 MB (10.7 MB file), BimCraft IFC 867 MB (22.5 MB), CadCraft DWG 250 MB (8.2 MB). A tab on a phone or an iPad is killed around 1 to 1.5 GB (Studio for iPad is milestone 09), and a 100 MB IFC would pass that today. Plan: tools/perf/io-bench.mjs and open-file.mjs record bytes per source MB per format at every release (PERF.6); targets: cc-dwg under 30x, cc-ifc under 20x (strings and the STEP line index kept once, not per entity), browser peak under 3x after PERF.7 to PERF.9; the apps say so before opening a file that will not fit (navigator.deviceMemory + the file's size), instead of a dead tab. Wave 3 (scale-1000x.md, apps-3d.md): cc-dwg 35 bytes of heap per file byte (76 MB → 2.6 GB), cc-ifc about 1 GB per 100 MB in the browser, ModelCraft about 2 KB per face, DXF 38 bytes per file byte, LandXML 14 times the file; point clouds 3.8 GB for 100 M points with the in-memory store. These are the per-format budget numbers.

– Planned – –
PlatformPERF.11 Link to PERF.11Comment on PERF.11 Website: /sitemap.xml takes 3.1 s and 6,042 SQL queries on every crawl

Measured 2026-11-08 (bin/admin-perf.php /sitemap): 3,118 ms, 6,042 queries (2,080 ms SQL): LibraryItems::browse x40 (one page of 100 per call, 1,293 ms: COUNT + LEFT JOIN library_versions + ORDER over 13,850 items each time), then per item LibraryVersions::byId, Auth::byId and LibraryAuthors::uuidFor (2,000 each). Crawlers fetch the sitemap all day; it is 474 KB of XML. Plan: one query for the library URLs (item slug/uuid + author uuid + current version date, joined, no per-row lookups), written to a cached file (storage/cache/sitemap.xml, rebuilt by cron hourly or on library publish) and served from there; keep the dynamic parts (news, tutorials, apps) as they are. Target under 50 ms, under 10 queries.

– Planned – –
PlatformPERF.12 Link to PERF.12Comment on PERF.12 Website: /library front page runs 83 queries (250 ms) — N+1 loads and a 51 ms stats query per visit

Measured 2026-11-08 (bin/admin-perf.php /library): 251 ms, 83 queries taking 130 ms: LibraryItems::browse x2 (55 ms: COUNT + LEFT JOIN + ORDER over 13,850 items), LibraryItems::publicStats 51 ms, AddonLibrary::all 9 ms, then Auth::byId x25, LibraryItems::byId x16, LibraryFiles::byId x15 for the cards. /library/browse and the category pages share browse(). Plan: batch the card lookups (one IN (...) per table), cache publicStats and AddonLibrary::all for 10 minutes (file cache in storage/, no APCu on this PHP), index the browse ORDER columns and make the LIKE search on 4 columns a FULLTEXT index; target under 60 ms and under 15 queries.

– Planned – –
PlatformPERF.13 Link to PERF.13Comment on PERF.13 Website: /tutorials spends 290 ms of PHP parsing every help Markdown file on every request

Measured 2026-11-08 (bin/admin-perf.php /tutorials): 292 ms, only 7 queries (2 ms); the time is Help::forApp x2 and Help::common x2 (core/classes/Help.php: glob the help folder, read and parse every .md topic, the shots map) for the index page. /tutorials/{app} and the in-app help panel pay the same per request. Plan: compile each build's help once (bin/build-help.php already exists for the compiled help.js) and cache Help::forApp/common per build stamp as JSON in storage/cache (or ship the parsed index with the build), so a request reads one file. Target under 30 ms.

– Planned – –
PlatformPERF.14 Link to PERF.14Comment on PERF.14 Lab: every /lab app page walks the a Discord member folder three times (181 ms of PHP, 2,938 files stat-ed)

Measured 2026-11-08 in-process for /lab/cadcraft: 181 ms of PHP: AppBuilds::headTags 34 ms (jsFilesDeep + filemtime of every a Discord member file for the import map's ?v=), devStamp 37 ms (path|size|mtime of every a Discord member file plus the shell), offlineFiles 22 ms + offline_size 42 ms (2,938 files), Lang 20 ms; the HTML is 1,039 KB (import map 105 KB, cc-lang 590 KB). Staff and lab testers only, and the lab deliberately never caches (Clear-Site-Data), so every reload pays it. Plan: one directory walk per request shared by headTags, devStamp and offlineFiles (a small in-request cache of [path, size, mtime]); PERF.2 and PERF.3 take the inline catalog and the offline list out of the page. Target under 60 ms.

– Planned – –
PlatformPERF.16 Link to PERF.16Comment on PERF.16 Static delivery: no Brotli (gzip only), 7-day cache on files that are already cache-busted

Measured 2026-11-08: app files come back Content-Encoding: gzip only (cadcraft.js 198 KB to 61 KB); mod_brotli is loaded but not configured, and Brotli typically takes another 15 to 20 % off JS and CSS (1.4 to 1.7 MB of modules per app start). Every ?v= file carries Cache-Control: public, max-age=604800 (7 days); frozen release files and ?v=-busted shell files never change under their URL, so they can be immutable for a year (fewer revalidations on the second visit). Plan (.htaccess + Apache conf, no code): Brotli for text/css, javascript, wasm, json, svg with gzip as the fallback (or pre-compressed .br/.gz next to release files written by bin/release-app.php, served with mod_rewrite, so compression happens once, not per request); Cache-Control immutable, max-age 1 year for /assets/apps/<slug>/<x.y>/ and ?v= URLs; keep 7 days for anything without a version in its URL. Measure with tools/perf/startup.mjs (bytes on the wire).

– Planned – –
PlatformPERF.18 Link to PERF.18Comment on PERF.18 CadCraft Studio start-up time: a startup log with timestamps in the desktop shell, measured on Windows and macOS

Not measurable on the VPS (Studio is a Windows/macOS/Linux desktop shell around the web apps; the page part is PERF.1 to PERF.4). KICKOFF line 196 already asks for a startup log a person can send. Plan: desktop-shell logs timestamps for process start, single-instance lock, window shown, first page request, app module running, first drawing paint; the About dialog shows the last start's total; owner measures a cold and a warm start on the Windows workstation and the Mac mini with the 0.9 build and records them in the release notes. Budget: window in under 1 s, app usable in under 3 s warm.

– Planned – –
PlatformPERF.15 Link to PERF.15Comment on PERF.15 "Save for offline" downloads 107 to 260 MB per app; 103 MB of CadCraft's 173 MB is compiled help in 52 languages

Measured 2026-11-08 (bin/offline-size.php --libs): CadCraft 0.8.2 offline set 173 MB in 2,077 files: app files 161 MB, libraries 9.6 MB (pdfjs 5.2, three 2.1), shell 2.7 MB. Of the app files, help/ is 103 MB (52 compiled help.<locale>.js of 2 to 3 MB each plus 395 .md sources) and lang/ 33 MB (55 locale files); the modules a person runs are 3.7 MB at the top level. BimCraft 0.8.1 is similar; a Discord member builds reach 260 MB; MarkupCraft 78 MB carries 11.9 MB of Tesseract OCR data. On a phone this is a long download for one language. Plan: the offline set keeps the chosen locale (its lang file and its help.<locale>.js) plus English, never all 52; help .md sources are not saved (the compiled help is what the panel reads); OCR language data per picked language; optional "all languages" switch for a shared classroom machine. AppBuilds::offlineFiles takes the locale (PERF.3 fetches the list on demand). Expected: CadCraft about 35 MB instead of 173 MB, with the same offline behaviour for that person. Test: bin/offline-size.php gains --locale and the service-worker test checks the saved copy opens the help in the picked language.

– Planned – –
Performance roadmap — wave 3 60
PlatformPERF.26 Link to PERF.26Comment on PERF.26 Scale: text writers return one string, so exports stop at 512 MB and hold twice the output

DXF (dxf.js:1324, dxf2000.js:437), LandXML (landxml.js:227), OBJ, DAE, USDA (usda-write.js:33), GeoJSON and gcode writers each build one string and return it; a 1,000,000-entity DXF export is near the V8 string limit and the string plus its Blob is twice the output in memory. Change: writers that yield chunks into a WritableStream (createWritable on a file handle when the host offers one, else a Blob built from parts), with the same report object. Pairs with the streaming readers row.

CadCraftModelCraftCivilCraft App codeOur engines Planned 4 – docs/0.9-sessions/perf-wave3/
PlatformPERF.44 Link to PERF.44Comment on PERF.44 Website: session_activity and analytics_visitors hold 1.6 M rows and 1,015 MB (83 % of the database), 42 % bots, no retention, one table never read

Measured: session_activity 1.02 M rows / 646 MB growing 51,086 rows a day (21,675 of them is_bot = 1), analytics_visitors 597k rows / 369 MB growing 38,644 a day because a cookie-less client gets a fresh visitor id on every request; the table is written on every page view (Analytics.php:75) and read nowhere. Nothing prunes either (no DELETE in bin/ or the classes except the smoke test's own rows). The report queries full-scan the table (EXPLAIN ANALYZE: summary 1.8 s, topPages 2.4 s, each audience group 1.7 s, tryOpens 1.3 s), so the nightly warm job is roughly 60 to 80 s of scans that push the whole table through a 1 GB server-wide buffer pool these two tables alone fill. CadCraft analytics is about 1.1 inserts a second, over half of all INSERTs on this MySQL, each an fsync (two autocommits per page view). At 10x the warm job takes ten minutes and evicts every other database on the server. Fix: (1) do not store bot page views as rows (count per day per bot name in a small table) and give a visitor with no cc_vid cookie no analytics_visitors row until the second request; (2) retention for humans (owner's number; 30 days for any bot rows kept) as monthly partitions by TO_DAYS(created_at) dropped with ALTER … DROP PARTITION, or a nightly batched DELETE on idx_created; (3) a daily rollup table (day, url, country, region, city, device, os, browser, referrer host, campaign, lang, is_bot, views, people) filled for yesterday only, so the dashboard and reports read at most 365 rows per group; (4) stop writing analytics_visitors or read it somewhere; drop the unused idx_session. Keep the privacy page true. Combines the SQL and server tracks (sql-audit.md 4, server-api.md 9).

– Site and services Planned 4 Owner: how long to keep page-view rows (400 days keeps the year-over-year comparison the analytics page offers). docs/0.9-sessions/perf-wave3/
PlatformPERF.50 Link to PERF.50Comment on PERF.50 Website: the Library at 1000x (1 M items, 2.8 M versions, 10 M files): what breaks and the design that does not

Scaling the measured plans linearly from 13,846 items / 27,940 versions / 108k files / 41k metric rows: browse sort plus COUNT plus categoryCounts 64+30+30 ms become 4.6+2.2+2.2 s per page (breaks at about 100x); LIKE search 52 ms becomes 3.7 s while FULLTEXT stays tens of ms (index about 1 GB at 1 M items with descriptions: budget it); the per-card N+1 stays about 450 statements per page but 450 round trips is the floor of every page; publicStats / inUse / makers / forUser full reads 42 ms become 3 s each; possibleDuplicates 159 ms becomes 16 s per /admin/library view; library_metrics at 2 M rows a day needs the daily rollup and a 90-day raw retention; /sitemap (PERF.11) must become a sitemap index of 50k-URL files written nightly, never rendered per request; hot data 5 to 8 GB against a 1 GB server-wide buffer pool (the MySQL settings row). Fine as is: PK and unique lookups (uq_slug, uq_uuid, uq_sha256, uq_item_version), int unsigned ids, the content-addressed file store, the events feed and the notification mailer (idx_feed, idx_mail keep them O(result)). This row is the design pass that ties the Library rows together and sets the data budget before the data arrives (docs/0.9-sessions/perf-wave3/sql-audit.md 12).

– Site and services Planned 5 The Library browse/search/index rows above first. docs/0.9-sessions/perf-wave3/
PlatformPERF.53 Link to PERF.53Comment on PERF.53 Apps: 29.6 MB of byte-identical files under different URLs across the eight releases, and every new release re-downloads 98 % unchanged files

tools/perf/addons-shared.mjs hashed every file of the eight current releases: 665 distinct contents under 2,163 URLs, 29.6 MB extra on the wire for a person who opens more than one app (cabinetcraft add-on in four apps 5.8 MB, dwg/ 3.0 MB, ifc schemas in four apps 2.3 MB, regs in four 2.3 MB, m3d 1.3 MB, crs-db.json 914 KB three times, host.js / addons.js / libitem.js eight times). Across releases: CadCraft 0.8.1 → 0.8.2 kept 2,084 of 2,127 files byte-identical (158 MB) and every one is re-downloaded under the new version URL; the same for every app and every "Save for offline" re-save (PERF.15). Vendor libraries are fine (one URL each, pinCurrent works). Change: a shared /assets/lib/<name>/<content-hash>/ URL for lib/* copies and shared add-ons (release-app.php pins it like vendor paths; the import map aliases ./dwg/x.js to it), or content-hashed file names so an unchanged file keeps its URL across releases. Both shrink the import map, which lists every file because ?v= busting needs an entry per module (499 entries / 48 KB in CadCraft, 772 / 78 KB in BimCraft per page view; AppBuilds.php:391-397).

CadCraftBimCraftModelCraftMarkupCraftTakeoffCraftCivilCraftDetailCraftPartCraft Site and servicesApp shell Planned 8 – docs/0.9-sessions/perf-wave3/
PlatformPERF.58 Link to PERF.58Comment on PERF.58 Apps: an installed add-on package is relinked from blob modules on every start (hvac 334 ms, plant 756 ms) and ships as base64 JSON

addons.js linkPackage turns each verified package into blob: module URLs every start: hvac 0.9.0 (193 files, 1.8 MB; 2.4 MB as base64 JSON) costs 334 ms per start (link 115, import 55, verify 6); plant 756 ms (import 447). The Ed25519 plus sha256 check is cheap (6 to 11 ms for 100 to 193 files); blob modules get no HTTP cache and no V8 code cache, so the cost repeats on every visit and grows with file count. Change: keep the signature check but serve verified packages from the service worker under a stable /addons/pkg/<sha>/<path> scope (or cache the linked texts and import() a persistent URL) so modules get code caching; stop base64 in the package JSON (binary zip, about 34 % smaller). AddonPackages.php, addons.js, sw.js.

CadCraftBimCraftModelCraftMarkupCraftTakeoffCraftCivilCraftDetailCraftPartCraft App shellSite and services Planned 3 – docs/0.9-sessions/perf-wave3/
PlatformPERF.59 Link to PERF.59Comment on PERF.59 Apps: no service worker until someone clicks "Save for offline"; every repeat visit is a cold start minus the 7-day HTTP cache

app-offline.js:160 registers /sw.js only on the click, and sw.js:46 installs nothing on its own; the PWA manifest promises more than the page delivers. Every visit refetches the 830 to 940 KB app page (PERF.2, PERF.3) and relies on the HTTP cache for the 300 to 500 module files (which Vary: Referer defeats, see the server rows). Change: register /sw.js on every /use page; cache-first for immutable URLs (?v= and pinned vendor/app folders: the worker already knows the rule, sw.js:33-40), stale-while-revalidate for the page; "Save for offline" stays the explicit full copy. Pairs with the shared-URL row (a shared lib URL is cached once for all apps) and the installed-package row.

CadCraftBimCraftModelCraftMarkupCraftTakeoffCraftCivilCraftDetailCraftPartCraft App shell Planned 3 – docs/0.9-sessions/perf-wave3/
PlatformPERF.68 Link to PERF.68Comment on PERF.68 Server: disk at 75 % with 90 GB reclaimable (a 56 GB Rust build tree, tmp/ build trees, both 0.8 downloads, a lang-overlay cache); logs rotated monthly

Measured: / is 290 of 388 GB. desktop-shell src-tauri target 56 GB (the forks' target moved to W: on 2026-11-08; this one did not; memory rule: never rebuild forks on the VPS), stores/build 18 GB, tmp build trees about 13 GB (editions, public-repos, studio-suite-0.9-a Discord member, devshell, live-apps-www*), downloads 0.8 and 0.8.1 both on disk (2.1 GB each; 0.7 and older moved to the CDN), three byte-identical frozen copies per app (hardlinking would save about 1.3 GB), tmp/cache/lang-overlay 981 MB with no TTL; access.log 345 MB a day uncompressed for a month (2.76 GB now). Noise: mec-broker logs two lines a minute when idle, a Discord member-sandbox-sync logs the same schema drift (team_join_codes.used_at) every 10 minutes, mail-poll logs a PHP array_merge(stdClass) error every 5 minutes (a ContactMail bug). Changes: move or delete the Rust target, clean tmp/ after each release, TTL on lang-overlay, hardlink identical files across frozen versions in bin/release-app.php, publish 0.8 downloads to the CDN like 0.7, weekly (or daily access) logrotate, quiet the idle broker line, fix the sandbox drift and the mail-poll error. About 90 GB back (75 % to about 52 %).

– Site and servicesTests and tooling Planned 1 Owner: /etc/logrotate.d is server-wide; tmp/downloads-replaced (4.7 GB) is the "never deleted" policy and stays. docs/0.9-sessions/perf-wave3/
Interface roadmap — wave 1 26
PlatformUI.2 Link to UI.2Comment on UI.2 One tear-off: every bar, menu, palette and panel moves to its own window the same way

Today there are four ways to put a piece of the interface in a window: the ribbon has its own tearOff()/dockRibbon() in app-workspace.js (window.open, stylesheet copy, key forwarding, about 60 lines), the toolbox, tool rows and status bar use app-workspace-popout.js popout(), the app panels use app-panels.js (its own ONE "panels window", adoptNode, Window Management API), and the classic toolbar and SuperCad walls use app-toolbar-tear.js and api.tearable(). Each copies stylesheets and theme differently, forwards keys differently and remembers (or does not remember) its window differently; closing behaviour differs too. Change: one window service in the shell (app-windows.js, grown from popout.js) that every piece uses: open from a click, move the nodes (handlers and state go along), mirror <html>/<body> attributes, stylesheets, interface size and icon style, forward keys that are not typing, give the window a title and the app's icon, dock back on close, on "Put it back" or by dragging the grip back over a drop target (UI.5). The ribbon, panels, toolbar and SuperCad code become callers of it. One "…" menu (shell-panel-menu) for all of them with the same entries in the same order: Move to a new window / Put it back / Float / Dock left / right / bottom / Hide. Test: the conformance test tears off every block that allows it and brings it back, in every layout.

CadCraftBimCraftModelCraftMarkupCraftTakeoffCraftCivilCraftDetailCraftPartCraftSuperCad Studio App shell Planned 4 – docs/0.9-sessions/interface-wave1/SUMMARY.md
PlatformUI.4 Link to UI.4Comment on UI.4 Studio: torn-off windows are real windows, placed on the right monitor and remembered, on Windows, macOS and Linux

In CadCraft Studio a window.open becomes a real Tauri window through on_new_window in desktop-shell src-tauri/src/lib.rs (built on about:blank; the engine loads the asked page into the window it is handed). This path has crashed Studio on Windows before (TakeoffCraft pop-up, 0.6 report) and the 0.8.1 hand-off was never tested on a Windows build. This row: the window service (UI.2/UI.3) in Studio = one Tauri window per torn-off piece with the app's icon and a title, placed on the monitor the person dragged to (Tauri monitor list, no Window Management permission prompt), its place remembered with the window ids that survive a restart (MCP-WINDOW-IDS), restored at start without a click (the desktop may do what the browser may not), closed with the main window, and a startup log line per window (PERF.18's log). Test on ws11a (two monitors) and the owner's Mac; tablets stay without pop-ups (the shell's mobile rule).

CadCraftBimCraftModelCraftMarkupCraftTakeoffCraftCivilCraftDetailCraftPartCraftSuperCad Studio Desktop host Planned 3 A Windows build and a hand test on two monitors (the pop-up hand-off is unverified since 0.8.1; see memory studio-popup-handoff-crash). docs/0.9-sessions/interface-wave1/SUMMARY.md
PlatformUI.21 Link to UI.21Comment on UI.21 One dock manager: a ribbon set becomes a palette and back; any tool group docks to a canvas edge, tabs, collapses, floats or takes a window

Owner 2026-11-09, on the reference at app.draftcraft.a Discord member: "the ability for a RIBBON set to turn into a palette, like in Adobe Photoshop or something similar, where you can dock panels/palettes, and in this particular case we can dock a ribbon to the top of the canvas." The idea: a ribbon group, a tool row, a toolbox group, Properties, the browser, the info box, the command line and a status strip are one thing, a DOCKABLE UNIT; a ribbon is units docked horizontally along the top of the canvas with a tab strip, a palette the same unit docked vertically in a side column, a tabbed panel several units in one slot, an icon rail a collapsed column, a floating palette a unit over the drawing, a window a unit on another monitor. Today each is its own block kind and code path (15 block kinds, four tear-off paths, the panel manager apart from the engine). Change: one dock manager in the shell (app-dock.js, grown from app-panels.js' dock / float / window logic and the engine's regions; SuperCad Studio's SC.2 panels, "everything is a panel that docks, tears off and groups", become a caller of it): zones = the four canvas edges plus the two panel columns, drawn as drop targets while dragging (UI.5); a unit dropped in a top or bottom zone lays out horizontally (the ribbon look), in a side zone vertically (icon + name rows, the palette look), on another unit it joins as a tab, on the rail it collapses to an icon, over the drawing it floats, past the window edge it tears off (UI.2/UI.3). The orientation belongs to the zone, the tools to the unit (format v2, UI.6), so the same Draw set is a ribbon group at the top and a palette at the side. The layout file says, per unit, which zone and in which order; the block kinds become presets of units in zones, so every built-in layout still reads and every adapter still fills them. Conformance: drag the Draw group from the ribbon to the left column and back in every app; a layout saved that way reloads the same.

CadCraftBimCraftModelCraftMarkupCraftTakeoffCraftCivilCraftDetailCraftPartCraftSuperCad Studio App shell Planned 8 UI.1 (the pattern) and UI.2 (one window service) first; UI.5 and UI.6 are built on this. docs/0.9-sessions/interface-wave1/SUMMARY.md
PlatformUI.22 Link to UI.22Comment on UI.22 The icon library: one drawing for every command, option and shell function in the eight apps, kept as data, the same in every layout and app

Owner 2026-11-09: "we need to create an entire library of icons (a task) that covers all of the application options, so that our icons are consistent regardless of the layout/app." What exists: app-workspace-icons.js holds 114 drawings on a 32-unit grid; about 270 specialist tools had no drawing by the 2026-11-05 count; the shell bar, More menu, panel tabs, status bar, menus and dialogs still use Bootstrap Icons (bi-*) and each app draws some of its own, so one command looks different from layout to layout and app to app. This row makes the library its own thing: (1) an inventory tool (tools/icons/inventory.mjs) reads every app's command registry, its toolbar, menu and toolbox definitions, the shell's bar buttons and panel tabs, Settings and the layout blocks, and writes docs/icons/INVENTORY.md: every command or option id, its apps, its drawing key or "missing"; nothing is drawn before the list exists; (2) the library in its own public repo (getcadcraft/icons, Apache-2.0, like every shared library): one SVG source per icon on the 32 grid with the five fills and two strokes as classes, names.json (key, name, aliases, the commands that use it), and a build that packs the set into app-workspace-icons.js, a sprite for the site and the add-ons kit, and the gallery data for UI.23; a hand edit of the packed file is refused by a check; (3) the drawings, under the UI.13 rules, in batches by app with the owner's look at each batch on the review sheet; shared verbs (move, copy, rotate, trim, offset, measure, zoom, undo) drawn once for every app; the shell's own set (home, find, help, settings, sun and moon, full screen, offline, problems, team, lessons, the AI and the panel buttons); (4) a lint in the release freeze: a registered command without a drawing, a drawing without a name, or a bi-* class left in shell or app chrome fails it; (5) the count in the release note (UI.18) comes from the inventory, never typed. Each app's own drawings are migrated or retired by its session.

CadCraftBimCraftModelCraftMarkupCraftTakeoffCraftCivilCraftDetailCraftPartCraftSuperCad Studio App shellApp codeTests and tooling Planned 10 UI.13 (the owner's drawing rules) first; UI.14 wires the result into every block. docs/0.9-sessions/interface-wave1/SUMMARY.md
PlatformUI.25 Link to UI.25Comment on UI.25 One state language: an action enables or disables menu items, shows and updates panels, and selects on the canvas; every unit follows the same state

Owner 2026-11-09: "remember that actions can enable or disable menu items or make panels show/update as well as selecting objects on the canvas." What exists: every app wires this by hand in its own code: Properties refreshes on the app's selection event, the project tree selects through app code, the command registry (ccInput) knows commands but no enabled or visible condition, menus and toolbars are static until an app toggles classes, contextual ribbon tabs do not exist (UI.11), Problems and the add-ons read their own events. Change: (1) one state in the shell (ccState): selection (ids, kinds, count), mode (model / paper, 2D / 3D), the active view, the current layer and tool, document dirty; the apps publish into it through the host adapter; nothing else writes it; (2) declarations as data: a command, menu item, button, ribbon tab or panel says when it is enabled, visible or shown (enabled: selection.count > 0; visible: selection.kind == wall; show: problems.count > 0) in the registry and the layout file (format v2), never in per-app DOM code; the dock manager applies them: items dim, contextual tabs appear and go (UI.11), panels show or refresh, badges count; (3) the reverse channel: a unit acts on the canvas through the host (select, reveal, highlight), so a Browser row, a Problems line, a schedule row or a search hit selects and zooms to the objects with the same undoable selection the pointer makes; (4) one action path: every button, menu item and shortcut runs the registry command, so one command in a ribbon, a palette, a menu and the status bar has one enabled state and one label; (5) a check (bin/test-shell-state.mjs) opens every app, selects through the host and asserts Modify enabled, Properties updated, the Browser row lit, a declared contextual tab shown, then selects from the panel and asserts the canvas selection. The mockup's demo shows the behaviour (click a wall, or its Browser row). SuperCad Studio's host is the same contract.

CadCraftBimCraftModelCraftMarkupCraftTakeoffCraftCivilCraftDetailCraftPartCraftSuperCad Studio App shellApp code Planned 5 UI.21 (units) and UI.6 (format v2) carry the declarations; each app publishes its state in its own session. docs/0.9-sessions/interface-wave1/SUMMARY.md
Suggest an item

Anyone can send one; no account and no name needed. The team reads each idea, and the ones we take on appear on this page. Please leave out web addresses.