Docs

App Template (Served Mockups) — Delivery Notes

Delivery summary for turning the business-theme mockups into a standalone, served app template. For the decision record read ADR-0016. This note says what changed and how it was proven.

Status

Implemented; static verification complete, in-app opener verified manually.

PieceState
New repo tranquil-app-template (git init, app/, automations/)✅ done
Move main-view.html + properties.html + mockup.css + fonts/ into app/✅ done
deno.jsondeno task dev serves app/ via npm:browser-sync (no package.json)✅ done
automations/open-app.js — opens both URLs into center + right dock, sets data-theme once✅ done + manually verified
Remove mockup machinery from tranquil-automations (mockups/, lib/mockups.js, lib/mockup-controls.js, config, auto-open, isMockupUrl)✅ done
Add tranquil-app-template to tranquil-dev.code-workspace✅ done
ADR-0016✅ written
Dev server serve + inject + watch, verified✅ passed
Business Themes & Mockups doc update to the served model⬜ follow-up

What & why

The two pages were file:// fixtures inside tranquil-automations (mockups/), auto-opened at startup and shipped in every automations release. They’re really the seed for building Tranquil apps, so they moved to their own repo where they’re developed and served on their own. See ADR-0016 for the decision and options.

The new repo

tranquil-app-template/
  deno.json              # deno task dev → npm:browser-sync serving app/ on :3000
  deno.lock              # the only committed lockfile (no package.json)
  .gitignore             # .DS_Store, node_modules/
  README.md
  app/                   # served web root
    main-view.html       #   → center pane
    properties.html      #   → right dock
    mockup.css
    fonts/               #   Inter + IBM Plex Mono woff2
  automations/
    open-app.js          # tranquil-automations script; opens both panes

Serving. One task, no Node toolchain:

{
  "tasks": {
    "dev": "deno run -A npm:browser-sync@^3.0.0 start --server app --port 3000 --files "app/**/*" --no-open --no-notify"
  }
}

Opening. open-app.js runs in Tranquil’s renderer sandbox (the atom global is injected by runScript in tranquil-automations/lib/tranquil-automations.js), so it needs no puppeteer / remote-debugging port — it just calls atom.workspace.open with the same location/allowedLocations/defaultLocation/hideURLBar opts the old host loader used, then sets data-theme once from the active UI theme.

Removal from tranquil-automations

All coupling was in lib/. Deleted mockups/, lib/mockups.js, lib/mockup-controls.js; then surgically stripped tranquil-automations.js (both requires, the showBusinessMockups config, mockupControls.activate(), and the addTrustedRoot/watchTheme/openMockups block) and pane-controls-capability.js (the isMockupUrl import + its predicate clause).

The one non-obvious trap. pane-controls-capability.js imported isMockupUrl from the deleted mockups.js. Deleting the files without also removing that require leaves a MODULE_NOT_FOUND at module load, which crashes activation and silently drops all automations commands. The import and its !isMockupUrl(urlOf(item)) && clause had to be removed together. With the clause gone, registerDefaultRemoteControls matches “has a webview and is not trusted” — which now also gives the served http://localhost:3000 pages their default URL-bar toggle for free.

Verified grep shows zero dangling references, and all edited files parse under babel.

browser-sync under Deno — the two gotchas

  1. The hoisted node-modules linker needs nodeModulesDir: "manual", which in turn needs a package.json + deno install. First attempt set "nodeModulesLinker": "hoisted" and Deno refused to start:

    error: The hoisted node_modules linker requires --node-modules-dir=manual.

    Since this repo is deliberately package.json-free, the fix is to omit both keys and let Deno run browser-sync straight from its global npm cache. (The www-tranquil hoisted+manual setup only applies when you keep a package.json, as SvelteKit does.)

  2. browser-sync only injects its live-reload <script> when the request’s Accept header includes text/html. A bare curl returns the un-injected page even though /browser-sync/browser-sync-client.js serves 200 — this looked like a broken injection but isn’t: real browsers and Tranquil webviews always send Accept: text/html. Confirm with curl -H 'Accept: text/html' (content-length grows).

A benign Ignored build scripts for packages: npm:fsevents warning prints on startup; chokidar falls back and file-watching still works.

How it was verified

Dev server (headless). Started deno task dev and probed with curl:

requestresult
main-view.html / properties.html / mockup.css / both fonts200, exact byte sizes
main-view.html with Accept: text/htmlreload snippet injected (15826 → 16373 bytes)
touch app/mockup.cssserver logs File event [change] : app/mockup.css

Opener (in-app, manual). First run threw “The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.” — the immediate executeJavaScript fired before the webview was dom-ready. Fixed by guarding the immediate apply() in a try/catch (the same swallow-and-retry the old mockups.js used) and letting the did-stop-loading listener re-apply. After the fix the user confirmed both panes open and theme correctly. This matches the known webview timing behaviour from the RPC work.

Follow-up

  • Update the Business Themes & Mockups doc: it still describes the pages as tranquil-automations file:// fixtures. Repoint it at the served tranquil-app-template model.