From 8d45e3b7b37b2996599b4f51ab678de8cf25398a Mon Sep 17 00:00:00 2001 From: CRT Date: Thu, 15 Oct 2026 04:27:29 +0800 Subject: [PATCH] README: real terminal shots (tools/readme-term-shots.mjs) instead of hand-drawn SVGs, a badge row The architecture and create-terminal SVGs were drawn by hand and their text overflowed. The quick start now shows the real output of npm create waybetter, rendered the way storebound renders its terminal shots; the layers stay a table. --- README.md | 15 ++- assets/readme/architecture.svg | 127 -------------------------- assets/readme/create-terminal.svg | 29 ------ assets/readme/term/create-app.txt | 11 +++ assets/readme/term/create-app.webp | Bin 0 -> 29250 bytes assets/readme/term/create-plugin.txt | 7 ++ assets/readme/term/create-plugin.webp | Bin 0 -> 17676 bytes tools/readme-term-shots.mjs | 105 +++++++++++++++++++++ 8 files changed, 135 insertions(+), 159 deletions(-) delete mode 100644 assets/readme/architecture.svg delete mode 100644 assets/readme/create-terminal.svg create mode 100644 assets/readme/term/create-app.txt create mode 100644 assets/readme/term/create-app.webp create mode 100644 assets/readme/term/create-plugin.txt create mode 100644 assets/readme/term/create-plugin.webp create mode 100644 tools/readme-term-shots.mjs diff --git a/README.md b/README.md index e72179a..163f9f8 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,12 @@ GPL-3.0-or-later · npm create waybetter

String packs · wayBetter for X

+

npm +license: GPL-3.0-or-later +runtime dependencies: 0 +Tauri 2 +platforms: macOS, Windows, Linux

+ You bring a site and a small adapter that says what the site is. wayBetter gives you the rest: a Tauri 2 window with tabs, split panes and every account signed in side by side; a page runtime with a plugin API, a theme engine and string packs; a signed Store with a safe install screen; backups, @@ -29,8 +35,6 @@ encrypted sync and signed updates; and the tooling to scaffold, sign, scan and r ## How it fits together -

Architecture: a Tauri 2 window with a trusted shell webview and untrusted site-tab webviews running the page runtime, the Rust host underneath that re-checks every command, the app's adapter on the side and the waybetter tooling

- A wayBetter app is one Tauri 2 window with several webviews. The framework has one piece for each layer and does not need to know which site you wrap. @@ -48,7 +52,7 @@ Details of every module are in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). npm create waybetter app kickapp -- --site kick.com --name "wayBetter for Kick" --yes ``` -

Terminal output: Created a wayBetter app in kickapp (32 files), then the next steps: cd kickapp, add the framework as a git submodule, npm install, npm run build, npm run tauri dev

+![npm create waybetter app: Created a wayBetter app in kickapp (32 files), then the next steps: cd kickapp, add the framework as a git submodule, npm install, npm run build, npm run tauri dev](assets/readme/term/create-app.webp) The same tool starts a plugin or a theme: @@ -57,6 +61,8 @@ npm create waybetter plugin -- --name "Hide Trends" # add --ts for Ty npm create waybetter theme -- --name "Midnight Mint" --accent "#3ddc97" ``` +![npm create waybetter plugin: a Hide Trends plugin file and how to install it](assets/readme/term/create-plugin.webp) + The app scaffold adds the framework as a git submodule at `waybetter/` by default (`--host-source path` and `--host-source git` are the alternatives). After `npm run tauri dev`, replace the placeholder selectors in `src/site.ts` and `src-tauri/src/site.rs`. All flags: @@ -241,6 +247,9 @@ bun run test:create # scaffolds each kind into temp folders and checks them a `test:create` also runs `cargo check` on a generated app (about a minute cold); `WAYBETTER_SKIP_CARGO_CHECK=1` skips that step. Requires Bun 1.4.2+, Node 24+ and Rust 1.88+. +The README's terminal images are real output: `node tools/readme-term-shots.mjs` runs the commands and +redraws `assets/readme/term/` (Google Chrome and cwebp). + ## Docs - [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md): every module of the host, runtime and shell diff --git a/assets/readme/architecture.svg b/assets/readme/architecture.svg deleted file mode 100644 index 9d64aef..0000000 --- a/assets/readme/architecture.svg +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - — ARCHITECTURE - One window, three layers, one small adapter. - - - - - The website you already use - loaded live from its exact https origin, never copied: x.com, kick.com, … - - - - TAURI 2 WINDOW · SYSTEM WEBVIEW - - - - Shell - packages/shell · local, trusted - - Tabs, split panes, address bar - Command palette, accounts, decks - Settings panel, theme builder - Store and the install screen - Workspaces, backup, updates - - the only webview allowed to change anything - - - - Site tabs - one webview + profile per tab · packages/runtime - - Plugin API - Theme engine - String packs - DOM hub - Fetch / XHR hub - Link routing - Accounts - UI kit - Deck columns - - untrusted: may only report about itself - - - - - - - NATIVE HOST · RUST - waybetter-host - crates/waybetter-host - - Every command re-checks its caller (webview label, exact origin) - Profiles, settings, plugins, themes, fonts, workspaces - Signed Store (Ed25519), backup, encrypted sync, signed updates - - - - all commands - a short, reviewed list - - - - YOUR APP - The adapter - what only your site knows - - site.rs · SiteSpec - hosts, account rules - - site.ts · SiteAdapter - selectors, API marks, links - - capabilities/*.json - who may call what - - - - - NPM · waybetter - The tooling - - npm create waybetter - waybetter dev --watch - waybetter store build|sign|verify - waybetter strings check - waybetter release - waybetter build-env - - diff --git a/assets/readme/create-terminal.svg b/assets/readme/create-terminal.svg deleted file mode 100644 index 1878c88..0000000 --- a/assets/readme/create-terminal.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - npm create waybetter - - $ npm create waybetter app kickapp -- --site kick.com --name "wayBetter for Kick" --yes - Created a wayBetter app in kickapp (32 files). - Next: - cd kickapp - git init && git submodule add https://git.crt.fyi/CRT/waybetter.git waybetter - npm install - npm run build - npm run tauri dev - then replace the PLACEHOLDER selectors in src/site.ts and src-tauri/src/site.rs - $ ▍ - - diff --git a/assets/readme/term/create-app.txt b/assets/readme/term/create-app.txt new file mode 100644 index 0000000..6468a2d --- /dev/null +++ b/assets/readme/term/create-app.txt @@ -0,0 +1,11 @@ +$ npm create waybetter app kickapp -- --site kick.com --name "wayBetter for Kick" --yes + +Created a wayBetter app in kickapp (32 files). + +Next: + cd kickapp + git init && git submodule add https://git.crt.fyi/CRT/waybetter.git waybetter + npm install + npm run build + npm run tauri dev + then replace the PLACEHOLDER selectors in src/site.ts and src-tauri/src/site.rs diff --git a/assets/readme/term/create-app.webp b/assets/readme/term/create-app.webp new file mode 100644 index 0000000000000000000000000000000000000000..1d5e274734603bad813e71ae96b4ee17adea87ec GIT binary patch literal 29250 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 z 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 D<;W`M literal 0 HcmV?d00001 diff --git a/tools/readme-term-shots.mjs b/tools/readme-term-shots.mjs new file mode 100644 index 0000000..6a4ee43 --- /dev/null +++ b/tools/readme-term-shots.mjs @@ -0,0 +1,105 @@ +#!/usr/bin/env node +// Terminal shots for the README: runs real `create-waybetter` commands in a throwaway folder and saves, per shot, +// assets/readme/term/.txt the cleaned output (first line "$ ", no ANSI, temp paths made short) +// assets/readme/term/.webp that text drawn as a terminal (dark), rendered by headless Google Chrome and +// encoded with cwebp (the smaller of lossy q80 and lossless) +// Fails when a command exits non-zero, its output lacks its expected marker, or Chrome / cwebp hang. +// node tools/readme-term-shots.mjs all shots +// node tools/readme-term-shots.mjs --text only the .txt files (no browser) +// node tools/readme-term-shots.mjs app only these shots +// Needs Google Chrome (or CHROME=) and cwebp on PATH for the images. +import { spawnSync } from 'node:child_process'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..'); +const CLI = join(ROOT, 'packages', 'create-waybetter', 'bin', 'create-waybetter.js'); +const OUT = join(ROOT, 'assets', 'readme', 'term'); +const CHROME = process.env.CHROME || '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'; +const TIMEOUT_MS = 60_000; +const log = m => console.log(`${new Date().toISOString().slice(11, 19)} [term-shots] ${m}`); + +const SHOTS = [ + { name: 'create-app', title: 'npm create waybetter', marker: 'Created a wayBetter app', + shown: 'npm create waybetter app kickapp -- --site kick.com --name "wayBetter for Kick" --yes', + argv: ['app', 'kickapp', '--site', 'kick.com', '--name', 'wayBetter for Kick', '--yes'] }, + { name: 'create-plugin', title: 'npm create waybetter', marker: 'hide-trends', + shown: 'npm create waybetter plugin -- --name "Hide Trends"', + argv: ['plugin', '--name', 'Hide Trends'] }, +]; + +const esc = s => s.replace(/&/g, '&').replace(//g, '>'); +function lineHtml(l) { + if (l.startsWith('$ ')) return `$ ${esc(l.slice(2))}`; + let h = esc(l); + h = h.replace(/\b(error|ERROR|failed)\b/g, m => `${m}`); + h = h.replace(/^(\s*)(Created|Wrote)\b/, (m, a, b) => `${a}${b}`); + h = h.replace(/^(\s{2,})(cd |npm |git |then )/, (m, a, b) => `${a}${b}`); + return h; +} +const page = (title, lines) => `
${esc(title)}
${lines.map(lineHtml).join('\n')}
`; + +function run(cmd, args, opts = {}) { + const r = spawnSync(cmd, args, { encoding: 'utf8', timeout: TIMEOUT_MS, ...opts }); + if (r.error) throw new Error(`${cmd}: ${r.error.message}`); + return r; +} + +function shoot(shot, work) { + const r = run(process.execPath, [CLI, ...shot.argv], { cwd: work, input: '', env: { ...process.env, NO_COLOR: '1', FORCE_COLOR: '0' } }); + const out = `${r.stdout}${r.stderr}`.replace(/\x1b\[[0-9;]*m/g, '').replaceAll(work + '/', '').replaceAll(work, '.').trimEnd(); + if (r.status !== 0) throw new Error(`${shot.name}: exit ${r.status}\n${out}`); + if (!out.includes(shot.marker)) throw new Error(`${shot.name}: output lacks "${shot.marker}"\n${out}`); + return [`$ ${shot.shown}`, ...out.split('\n')]; +} + +function render(shot, lines) { + const tmp = mkdtempSync(join(tmpdir(), 'wb-term-')); + try { + const html = join(tmp, 'page.html'), png = join(tmp, 'shot.png'); + writeFileSync(html, page(shot.title, lines)); + // Height: bar + padding + lines; a little spare, the page background is the frame. + const height = Math.ceil(24 * 2 + 38 + 36 + lines.length * 13.5 * 1.75 + 8); + run(CHROME, ['--headless=new', '--disable-gpu', '--hide-scrollbars', '--force-device-scale-factor=2', `--window-size=1008,${height}`, `--screenshot=${png}`, `file://${html}`]); + if (!existsSync(png)) throw new Error(`${shot.name}: Chrome wrote no screenshot`); + const best = ['q80', 'lossless'].map(mode => { + const file = join(tmp, `${mode}.webp`); + const args = mode === 'q80' ? ['-q', '80', '-m', '6'] : ['-lossless', '-z', '9']; + const c = run('cwebp', ['-quiet', ...args, '-resize', '1600', '0', png, '-o', file]); + if (c.status !== 0) throw new Error(`cwebp ${mode}: ${c.stderr}`); + return { file, bytes: statSync(file).size }; + }).reduce((a, b) => (b.bytes < a.bytes ? b : a)); + writeFileSync(join(OUT, `${shot.name}.webp`), readFileSync(best.file)); + return best.bytes; + } finally { rmSync(tmp, { recursive: true, force: true }); } +} + +const args = process.argv.slice(2); +const textOnly = args.includes('--text'); +const only = args.filter(a => !a.startsWith('--')); +const shots = only.length ? SHOTS.filter(s => only.includes(s.name)) : SHOTS; +if (only.length && shots.length !== only.length) throw new Error(`unknown shot(s); known: ${SHOTS.map(s => s.name).join(', ')}`); +mkdirSync(OUT, { recursive: true }); +const work = mkdtempSync(join(tmpdir(), 'wb-readme-')); +try { + for (const shot of shots) { + const lines = shoot(shot, work); + writeFileSync(join(OUT, `${shot.name}.txt`), lines.join('\n') + '\n'); + log(`${shot.name}: ${lines.length} lines${textOnly ? '' : `, ${Math.round(render(shot, lines) / 1024)} KB webp`}`); + } +} finally { rmSync(work, { recursive: true, force: true }); }