create-bridgething 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,22 +1,26 @@
1
1
  # create-bridgething
2
2
 
3
- Scaffold a new [bridgething](https://github.com/JoeyEamigh/bridgething) webapp, a
4
- single-page app that runs on the kiosk chromium of a Spotify Car Thing and talks
5
- to the on-device daemon. The template ships React + Vite + Tailwind v4 with
6
- [`@bridgething/client`](https://www.npmjs.com/package/@bridgething/client)
7
- preinstalled.
3
+ Scaffold a [bridgething](https://github.com/JoeyEamigh/bridgething) webapp for
4
+ the Spotify Car Thing: React, Vite, Tailwind v4, and
5
+ [`@bridgething/client`](https://www.npmjs.com/package/@bridgething/client).
8
6
 
9
7
  ```sh
10
8
  bun create bridgething my-app
11
9
  ```
12
10
 
13
- ```sh
14
- npm create bridgething@latest my-app
15
- ```
11
+ | flag | what you get |
12
+ | -------------- | --------------------------------------------- |
13
+ | `--launcher` | A replacement home screen |
14
+ | `--overlay` | System UI drawn over every webapp |
15
+ | `--extension` | A desktop-side Deno process beside the webapp |
16
+ | `--no-install` | Skip `bun install` |
17
+ | `--no-git` | Skip `git init` |
18
+
19
+ `--extension` combines with `--launcher`, `--overlay`, or a plain webapp.
16
20
 
17
- The generated project includes `bun run push` to deploy the built webapp to a
18
- connected Car Thing, `bun run share` to share it with the community, and
19
- `bun run update` to bring the connected device to the latest bridgething release.
21
+ The project ships `bun run dev`, `build`, `push` (install on a connected Car
22
+ Thing), `share` (zip for the store), and `update` (bring the device to the
23
+ latest release).
20
24
 
21
- - Full docs: <https://bridgething.com/docs>
25
+ - Docs: <https://bridgething.com/docs>
22
26
  - Source: <https://github.com/JoeyEamigh/bridgething>
package/dist/index.mjs CHANGED
@@ -7,6 +7,29 @@ import { v7 } from "uuid";
7
7
  //#region src/index.ts
8
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
9
  const TEMPLATE_DIR = resolve(__dirname, "..", "template");
10
+ const EXTENSION = {
11
+ dir: "template-extension",
12
+ manifest: {
13
+ extension: {
14
+ entry: "extension/desktop.mjs",
15
+ permissions: ["all"],
16
+ api: 1
17
+ },
18
+ config: [{
19
+ type: "string",
20
+ data: {
21
+ key: "greeting",
22
+ label: "Greeting the extension sends on connect"
23
+ }
24
+ }]
25
+ },
26
+ dependencies: { "@bridgething/extension": `^${JSON.parse(readFileSync(resolve(__dirname, "..", "package.json"), "utf8")).version}` },
27
+ devDependencies: {
28
+ deno: "2.9.6",
29
+ esbuild: "^0.28.2"
30
+ },
31
+ summary: "native extension (a desktop-side Deno process)"
32
+ };
10
33
  const VARIANTS = {
11
34
  app: { summary: "webapp" },
12
35
  launcher: {
@@ -32,10 +55,12 @@ function parseArgs(argv) {
32
55
  let install = true;
33
56
  let git = true;
34
57
  let variant = "app";
58
+ let extension = false;
35
59
  for (const arg of argv) if (arg === "--no-install") install = false;
36
60
  else if (arg === "--no-git") git = false;
37
61
  else if (arg === "--launcher") variant = "launcher";
38
62
  else if (arg === "--overlay") variant = "overlay";
63
+ else if (arg === "--extension") extension = true;
39
64
  else if (arg === "--help" || arg === "-h") {
40
65
  printHelp();
41
66
  process.exit(0);
@@ -52,11 +77,12 @@ function parseArgs(argv) {
52
77
  target: positional[0],
53
78
  install,
54
79
  git,
55
- variant
80
+ variant,
81
+ extension
56
82
  };
57
83
  }
58
84
  function printHelp() {
59
- console.log(`Usage: create-bridgething <target-dir> [--launcher | --overlay] [--no-install] [--no-git]
85
+ console.log(`Usage: create-bridgething <target-dir> [--launcher | --overlay] [--extension] [--no-install] [--no-git]
60
86
 
61
87
  Scaffold a new bridgething webapp at <target-dir>.
62
88
 
@@ -67,6 +93,10 @@ Variants:
67
93
  --overlay A system overlay. Ships an 'overlay.js' the daemon injects
68
94
  into every webapp, replacing the built-in one.
69
95
 
96
+ Add-ons (combine with any variant):
97
+ --extension A native extension: a Deno process the desktop app runs
98
+ alongside the webapp, with host access the manifest declares.
99
+
70
100
  Options:
71
101
  --no-install Skip 'bun install' after copying.
72
102
  --no-git Skip 'git init' after copying.
@@ -79,23 +109,48 @@ function patchJson(path, patch) {
79
109
  ...patch
80
110
  }, null, 2)}\n`);
81
111
  }
112
+ function patchPackage(target, patch) {
113
+ const path = join(target, "package.json");
114
+ const pkg = JSON.parse(readFileSync(path, "utf8"));
115
+ patchJson(path, {
116
+ scripts: {
117
+ ...pkg.scripts,
118
+ ...patch.scripts
119
+ },
120
+ dependencies: sortKeys({
121
+ ...pkg.dependencies,
122
+ ...patch.dependencies
123
+ }),
124
+ devDependencies: sortKeys({
125
+ ...pkg.devDependencies,
126
+ ...patch.devDependencies
127
+ })
128
+ });
129
+ }
130
+ function sortKeys(record) {
131
+ return Object.fromEntries(Object.entries(record).sort(([a], [b]) => a.localeCompare(b)));
132
+ }
133
+ function overlayTemplate(target, dir, subs) {
134
+ copyTemplate(resolve(__dirname, "..", dir), target, subs);
135
+ const appendPath = join(target, "_claude_append.md");
136
+ if (!existsSync(appendPath)) return;
137
+ const claudePath = join(target, "CLAUDE.md");
138
+ writeFileSync(claudePath, `${readFileSync(claudePath, "utf8").trimEnd()}\n\n${readFileSync(appendPath, "utf8")}`);
139
+ rmSync(appendPath);
140
+ }
82
141
  function applyVariant(target, variant, subs) {
83
142
  const spec = VARIANTS[variant];
84
- if (spec.dir) copyTemplate(resolve(__dirname, "..", spec.dir), target, subs);
85
- const appendPath = join(target, "_claude_append.md");
86
- if (existsSync(appendPath)) {
87
- const claudePath = join(target, "CLAUDE.md");
88
- writeFileSync(claudePath, readFileSync(claudePath, "utf8") + readFileSync(appendPath, "utf8"));
89
- rmSync(appendPath);
90
- }
143
+ if (spec.dir) overlayTemplate(target, spec.dir, subs);
91
144
  if (spec.manifest) patchJson(join(target, "public", "manifest.json"), spec.manifest);
92
- if (spec.scripts) {
93
- const pkgPath = join(target, "package.json");
94
- patchJson(pkgPath, { scripts: {
95
- ...JSON.parse(readFileSync(pkgPath, "utf8")).scripts,
96
- ...spec.scripts
97
- } });
98
- }
145
+ if (spec.scripts) patchPackage(target, { scripts: spec.scripts });
146
+ }
147
+ function applyExtension(target, subs) {
148
+ overlayTemplate(target, EXTENSION.dir, subs);
149
+ patchJson(join(target, "public", "manifest.json"), EXTENSION.manifest);
150
+ patchPackage(target, {
151
+ dependencies: EXTENSION.dependencies,
152
+ devDependencies: EXTENSION.devDependencies
153
+ });
99
154
  }
100
155
  const BINARY_EXT = new Set([
101
156
  ".ttf",
@@ -168,7 +223,9 @@ function main() {
168
223
  console.log(`scaffolding ${projectName} (${webappUuid}) in ${target}`);
169
224
  copyTemplate(TEMPLATE_DIR, target, subs);
170
225
  applyVariant(target, args.variant, subs);
171
- console.log(` ✓ template copied (${VARIANTS[args.variant].summary})`);
226
+ if (args.extension) applyExtension(target, subs);
227
+ const shape = args.extension ? `${VARIANTS[args.variant].summary} + ${EXTENSION.summary}` : VARIANTS[args.variant].summary;
228
+ console.log(` ✓ template copied (${shape})`);
172
229
  linkAgentAliases(target);
173
230
  console.log(" ✓ agent guides linked (CLAUDE.md, AGENTS.md, /bridgething skill)");
174
231
  if (args.git) if (run("git", ["init", "--quiet"], target)) console.log(" ✓ git initialized");
@@ -182,7 +239,8 @@ function main() {
182
239
  Done! Next steps:
183
240
 
184
241
  cd ${args.target}
185
- ${args.install ? "" : " bun install\n"} bun run dev # local dev server (http://localhost:5173/)
242
+ ${args.install ? "" : " bun install\n"} bun run dev # local dev server (http://localhost:5173/) against the connected Car Thing
243
+ bun run dev:device # the same server on the Car Thing's own screen, hot reload included
186
244
 
187
245
  Open this folder with your coding agent (Claude Code, Codex, opencode, ...).
188
246
  It reads CLAUDE.md / AGENTS.md and the /bridgething skill in .claude/skills
@@ -193,14 +251,21 @@ driving the app, and installing and sharing it.
193
251
  bun run push <addr> # build + install onto a connected Car Thing (default bridgething.local)
194
252
  bun run share # build first, then zip dist/ to hand to friends
195
253
  bun run update # bring the connected Car Thing to the latest bridgething release
196
- ${args.variant === "app" ? "" : `
254
+ ${args.extension ? `
255
+ 'extension/main.ts' is the desktop-side half: a Deno process the bridgething
256
+ desktop app runs alongside this webapp, with the host access 'manifest.json'
257
+ declares. 'bun run dev' and 'bun run dev:device' also run it, rebuilt on every
258
+ save and wired to the connected Car Thing, so both halves iterate together.
259
+ 'bun run build' bundles it to dist/extension/desktop.mjs.
260
+ ` : ""}${args.variant === "app" ? "" : `
197
261
  'bun run push' also claims the device's ${args.variant} slot, so this is live the
198
262
  moment it lands. 'bun run push --release' hands the slot back to the built-in
199
263
  ${args.variant === "launcher" ? "hub" : "overlay"}, which is how you recover if a build of this wedges the screen.
200
264
  The companion phone app can do the same thing.
201
265
  `}
202
- The starter App connects to ws://127.0.0.1:8891/ on the device, and to
203
- ws://<device-ip>:8891/ in dev when you set VITE_BRIDGETHING_URL.
266
+ The starter App connects to the daemon through daemonUrl() in src/daemon.ts: the
267
+ local daemon on the device, and the dev server's proxy to the Car Thing over USB
268
+ under bun run dev (SUPERBIRD_HOST picks another device).
204
269
  `);
205
270
  }
206
271
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bridgething",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "description": "Scaffold a new bridgething webapp (React + Vite + Tailwind v4)",
6
6
  "license": "MIT",
@@ -25,18 +25,24 @@
25
25
  "files": [
26
26
  "dist",
27
27
  "template",
28
+ "template-extension",
28
29
  "template-launcher",
29
30
  "template-overlay"
30
31
  ],
31
32
  "scripts": {
32
- "prebuild": "bun scripts/sync-push.ts",
33
+ "prebuild": "bun scripts/sync-shared.ts",
33
34
  "build": "tsdown",
34
35
  "dev": "tsdown --watch",
35
- "typecheck": "tsc --noEmit"
36
+ "typecheck": "tsc --noEmit",
37
+ "test": "bun test"
36
38
  },
37
39
  "devDependencies": {
40
+ "@bridgething/extension": "0.12.0",
41
+ "@msgpack/msgpack": "^3.1.3",
42
+ "@types/bun": "^1.4.0",
38
43
  "@types/node": "^26.1.1",
39
44
  "@types/uuid": "^11.0.0",
45
+ "esbuild": "^0.28.2",
40
46
  "tsdown": "^0.21.10"
41
47
  },
42
48
  "peerDependencies": {
@@ -1,95 +1,71 @@
1
1
  # Building this bridgething webapp
2
2
 
3
- You are helping build a **bridgething webapp**: a single-page web UI for the
4
- Spotify Car Thing. It runs full-screen in a chromium kiosk on the device and
5
- talks to the on-device daemon over a local WebSocket using `@bridgething/client`.
6
- This file is always loaded; it holds the constraints. The `/bridgething` skill
7
- goes deep on the how-to: the client API, running and driving the app, and
8
- shipping it.
9
-
10
- ## The device you are targeting
11
-
12
- - **Screen: 800x480, landscape.** Fixed. Design for exactly this. The window
13
- never resizes; there is no responsive breakpoint to chase.
14
- - **One page.** The kiosk shows exactly one webapp at a time. In-app views are
15
- fine, but there are no browser tabs, popups, or second windows.
16
- - **Physical controls arrive as ordinary browser events.** Listen with a
17
- `keydown` handler and a `wheel` handler on `window`.
18
- - Preset buttons **1 2 3 4** -> `keydown` key `"1"` `"2"` `"3"` `"4"`.
19
- - **Mode** button -> `keydown` key `"m"`. (Pressing it 5 times fast is a
20
- system gesture that jumps back to the launcher, so do not build anything
21
- that depends on rapid repeated `m`.)
22
- - **Back** button -> `keydown` key `"Escape"`.
23
- - **Rotary wheel** -> horizontal scroll: `wheel` events with `deltaX`. This is
24
- the primary way users move through lists; make horizontal wheel scroll work.
25
- - **Touch** works normally (pointer/touch events).
26
- - **No keyboard, no mouse.** Those five controls plus touch are the whole input
27
- surface. There is no text entry unless you build an on-screen one.
28
-
29
- ## The SDK: `@bridgething/client`
3
+ A bridgething webapp is one page running full-screen in the chromium kiosk on a
4
+ Spotify Car Thing. It reaches the on-device daemon through `@bridgething/client`.
5
+
6
+ ## The device
7
+
8
+ The screen is 800x480, landscape, and never resizes. The kiosk shows one webapp,
9
+ so build in-app views rather than tabs or windows. Add an on-screen keyboard if
10
+ the app needs text entry.
11
+
12
+ Listen with a `keydown` handler and a `wheel` handler on `window`.
13
+
14
+ | Control | Event |
15
+ | ------------ | ------------------------------------- |
16
+ | Preset 1-4 | `keydown` key `"1"` `"2"` `"3"` `"4"` |
17
+ | Mode | `keydown` key `"m"` |
18
+ | Back | `keydown` key `"Escape"` |
19
+ | Rotary wheel | `wheel` with horizontal `deltaX` |
20
+ | Touch | pointer and touch events |
21
+
22
+ Make horizontal wheel scroll move through the main list. Five fast presses of
23
+ Mode returns to the launcher.
24
+
25
+ ## The client
30
26
 
31
27
  ```ts
32
28
  import { BridgethingClient } from '@bridgething/client';
33
- const client = new BridgethingClient(); // auto-connects to the daemon, auto-reconnects
29
+ import { useMemo } from 'react';
30
+
31
+ import { daemonUrl } from './daemon';
32
+
33
+ const client = useMemo(() => new BridgethingClient({ url: daemonUrl() }), []);
34
34
  ```
35
35
 
36
- Construct it once and reuse it. It defaults to the on-device daemon; in dev you
37
- point it at your device with `VITE_BRIDGETHING_URL` (the starter `App.tsx`
38
- already does this). Do not hardcode a WebSocket URL.
39
-
40
- It is fully typed with a doc comment on every surface, method, and field. Read
41
- those declarations directly - you have no editor to hover in:
42
-
43
- - `node_modules/@bridgething/client/dist/dispatch.generated.d.ts` - every
44
- `client.<surface>.<method>` and event, with docs.
45
- - `node_modules/@bridgething/lib/dist/bindings/*.d.ts` - the payload and reply
46
- types (`PlayerState`, `MediaItem`, ...), with per-field docs.
47
-
48
- 18 surfaces: `player asset config store capabilities library audio notifications
49
- phone geo net hardware bluetooth system time voice webapp forward`. Each method
50
- is one of three shapes:
51
-
52
- - **events**: `client.<s>.onXxx(handler)` returns an unsubscribe fn; or
53
- `client.<s>.subscribe({ onXxx, ... })`.
54
- - **requests**: `await client.<s>.xxx(req)` returns `{ ok: true, response }` or
55
- `{ ok: false, kind, error }` - always check `.ok`.
56
- - **commands**: `await client.<s>.xxx(payload)` returns `void` (fire-and-forget).
57
-
58
- Now-playing and library data come from the **connected phone's** Spotify. Assume
59
- a phone may not be connected: handle the empty/disconnected state gracefully (the
60
- starter shows a "connect a phone" placeholder). Fetch artwork by opaque asset id
61
- via `client.asset.get`; never build image URLs by hand.
62
-
63
- Run `/bridgething` for the cookbook, the dev loop, and shipping; grep the `.d.ts`
64
- files for a specific method or type.
65
-
66
- ## `manifest.json` (in `public/`)
67
-
68
- - `id` - baked in at scaffold, unique to this project. **Never change it.**
69
- - `name`, `version`, `description`, `icon` - cosmetic / store metadata.
70
- - `config` - user-tunable settings (each becomes a `client.config` value).
71
- - `permissions` - capabilities you need (e.g. `net.fetch`, `net.proxy`, `geo`).
72
- - `art: { heroPx, thumbPx }` - the pixel sizes you want artwork delivered at.
73
- - `settings` - one self-contained HTML file (built from `settings/`) the
74
- companion phone app renders as this webapp's settings page. It talks to the
75
- companion over `@bridgething/client/settings`, not the on-device SDK. Capped
76
- at 1 MiB at install. It loads from a `file://` origin: websocket APIs work
77
- from it, but plain HTTP fetch is CORS-gated (`Origin: null`) - see the
78
- network caveat in the `/bridgething` skill's sdk reference.
36
+ Construct it once and reuse it. It connects and reconnects on its own. Call
37
+ `daemonUrl()` instead of a literal `ws://` address.
79
38
 
80
- ## Workflow
39
+ Now-playing and library data come from the phone's Spotify, so render a
40
+ placeholder when no phone is connected. Fetch artwork with `client.asset.get`
41
+ using the opaque id on the track.
42
+
43
+ Every surface: `player asset config store doc capabilities library audio
44
+ notifications phone peer geo net hardware bluetooth system time voice lyrics
45
+ webapp forward`. Each method is an event, a request, or a command.
46
+
47
+ Methods, types, and examples: `.claude/skills/bridgething/reference/sdk.md`.
81
48
 
82
- - `bun run dev` - vite dev server. Iterate here. Use `/bridgething` for the loop
83
- of seeing the screen and pressing the buttons.
84
- - `bun run build` - production bundle into `dist/`.
85
- - `bun run push` - build + install onto a connected Car Thing (see `/bridgething`).
86
- - `bun run update` - update the connected device to the latest bridgething release
87
- (device firmware, not your webapp; see `/bridgething`).
49
+ ## `public/manifest.json`
50
+
51
+ - `id` identifies this webapp on the device. Keep it.
52
+ - `version` tells builds apart. Raise it before sharing an update.
53
+ - `config` declares the settings the companion app edits and `client.config`
54
+ reads.
55
+ - `permissions` grants `geo` and `net.proxy`.
56
+ - `art.heroPx` and `art.thumbPx` are the sizes artwork arrives at.
57
+ - `settings` names the page built from `settings/`, capped at 1 MiB. It talks to
58
+ the companion app through `@bridgething/client/settings`.
59
+
60
+ ## Workflow
88
61
 
89
- ## Do not
62
+ - `bun run dev` serves at `http://localhost:5173/` against the connected Car
63
+ Thing.
64
+ - `bun run dev:device` shows that server on the device's own screen.
65
+ - `bun run build` writes `dist/`.
66
+ - `bun run push` builds and installs onto the connected device.
67
+ - `bun run share` zips `dist/`.
68
+ - `bun run update` brings the device to the latest bridgething release.
90
69
 
91
- - Fight the 800x480 viewport or assume any other size.
92
- - Hardcode `ws://...`; use the SDK default + `VITE_BRIDGETHING_URL`.
93
- - Assume a phone is always connected.
94
- - Build image URLs by hand; fetch by opaque asset id.
95
- - Rely on rapid repeated `m` (system launcher gesture).
70
+ Running and driving the app: `.claude/skills/bridgething/reference/develop.md`.
71
+ Push, zip, update: `.claude/skills/bridgething/reference/ship.md`.
@@ -1,14 +1,13 @@
1
1
  # **PROJECT_NAME**
2
2
 
3
- A bridgething webapp scaffolded with `create-bridgething`.
3
+ A bridgething webapp scaffolded with `create-bridgething`. It runs full-screen in
4
+ the chromium kiosk on a Spotify Car Thing and talks to the on-device daemon
5
+ through [`@bridgething/client`](https://github.com/JoeyEamigh/bridgething).
4
6
 
5
- Stack: React 19 + Vite + Tailwind v4 + TypeScript strict, with
6
- [`@bridgething/client`](https://github.com/JoeyEamigh/bridgething) preinstalled.
7
+ Stack: React 19, Vite, Tailwind v4, TypeScript strict.
7
8
 
8
- ## Building with an agent
9
-
10
- Open this folder with your coding agent (Claude Code, Codex, opencode, ...). It
11
- reads `CLAUDE.md` / `AGENTS.md` and the `/bridgething` skill.
9
+ Open this folder with your coding agent. It reads `CLAUDE.md` or `AGENTS.md` and
10
+ the `/bridgething` skill.
12
11
 
13
12
  ## Develop
14
13
 
@@ -17,54 +16,42 @@ bun install
17
16
  bun run dev
18
17
  ```
19
18
 
20
- Opens at http://localhost:5173/. The starter `App.tsx` connects to
21
- `ws://<host>/` (the daemon's local WebSocket on port 8891 of the device
22
- itself). To dev against a remote device, set:
19
+ Vite serves at http://localhost:5173/ with hot reload, against the daemon on the
20
+ Car Thing plugged in over USB. Set `SUPERBIRD_HOST` to target another device, or
21
+ `BRIDGETHING_DAEMON_URL` to reach a daemon elsewhere.
23
22
 
24
23
  ```bash
25
- VITE_BRIDGETHING_URL=ws://<device-ip>:8891/ bun run dev
24
+ bun run dev:device
26
25
  ```
27
26
 
28
- ## Push to a device
27
+ The same server, shown on the Car Thing's own screen, hot reload included.
28
+ Ctrl-C hands the screen back to the installed build.
29
29
 
30
- ```bash
31
- bun run push
32
- ```
30
+ When the project ships an extension (`extension/main.ts`), both commands bundle
31
+ it on every save and run it under Deno with the permissions the manifest
32
+ declares.
33
33
 
34
- `push` builds `dist/`, rsyncs it into `/var/bridgething/webapps/<manifest-id>/`
35
- on the Car Thing, and switches the kiosk to your app. Pass an IP address to target
36
- something other than `bridgething.local` over USB.
37
-
38
- ## Share
34
+ ## Push, share, update
39
35
 
40
36
  ```bash
37
+ bun run push # build, copy to the Car Thing, switch the kiosk to it
41
38
  bun run build
42
- bun run share
43
- ```
44
-
45
- `share` writes `<name>-<version>.zip` from `dist/`. Anyone with a bridgething Car
46
- Thing installs it from the app.
47
-
48
- ## Update the device
49
-
50
- ```bash
51
- bun run update
39
+ bun run share # write <name>-<version>.zip from dist/
40
+ bun run update # bring the device to the latest bridgething release
52
41
  ```
53
42
 
54
- `update` runs [`@bridgething/updater`](https://www.npmjs.com/package/@bridgething/updater)
55
- to bring the connected Car Thing to the latest bridgething release. Multiple devices: `bun run update -- --host ws://bridgething-<serial>.local:8892/`.
43
+ `push` targets `bridgething.local` over USB; pass a host or IP address for
44
+ another device. Anyone with a bridgething Car Thing installs the zip from the
45
+ companion app. For one device out of several,
46
+ `bun run update -- --host ws://bridgething-<serial>.local:8892/`.
56
47
 
57
48
  ## Layout
58
49
 
59
- - `src/App.tsx` - starter UI: subscribes to `client.player.onSnapshot`,
60
- fetches artwork via `client.asset.get`, exposes transport controls.
61
- - `src/index.css` - `@import "tailwindcss";`.
62
- - `vite.config.ts` - vite + tailwind plugin, `es2022` target.
63
- - `index.html` - 800x480 viewport, no overscroll, no tap highlight.
64
- - `settings/` - the companion-side settings page (preact), built by
65
- `vite.settings.config.ts` into a single self-contained `dist/settings.html`.
66
- It reads and writes settings over `@bridgething/client/settings`.
67
-
68
- `bun run build` runs both configs: the main app into `dist/`, then the settings
69
- page as `dist/settings.html`. `manifest.json`'s `settings` field points the
70
- companion at it.
50
+ - `src/App.tsx` subscribes to `client.player.onSnapshot`, fetches artwork through
51
+ `client.asset.get`, and draws transport controls.
52
+ - `src/daemon.ts` returns the daemon URL.
53
+ - `public/manifest.json` carries the webapp id, version, config schema, and
54
+ permissions.
55
+ - `settings/` is the settings page the companion app renders, built to
56
+ `dist/settings.html`.
57
+ - `index.html` and `vite.config.ts` fix the 800x480 viewport and the build target.
@@ -1,25 +1,20 @@
1
1
  ---
2
2
  name: bridgething
3
- description: Build, run, and ship a bridgething webapp for the Spotify Car Thing. Covers @bridgething/client (the SDK a webapp uses to reach the on-device daemon - now-playing, artwork, storage, settings, networking, all 18 surfaces), the loop for running the app and driving its 800x480 screen and physical controls from a browser you control, and installing the built app onto a device or packaging it as a shareable zip. Use whenever calling the daemon, running or previewing the app, pressing its controls, or pushing it to hardware.
3
+ description: Build, run, and ship a bridgething webapp for the Spotify Car Thing. Use for @bridgething/client calls (now-playing, transport, artwork, storage, user settings, networking, every surface), running the dev server and driving the 800x480 screen and its physical controls, pushing the built app to a device or packaging a shareable zip, and writing the desktop-side Deno extension a webapp can ship.
4
4
  ---
5
5
 
6
6
  # Building a bridgething webapp
7
7
 
8
- A bridgething webapp is a single-page React UI that runs full-screen in the
9
- device's chromium kiosk and reaches the on-device daemon through one typed
10
- client. You build it against a browser on your own machine and push it to real
11
- hardware only for final checks.
12
-
13
- Three jobs. Read the reference file for the one in front of you:
14
-
15
- - **Call the daemon** - now-playing, transport, artwork, storage, settings,
16
- networking, and the full 18-surface index: [reference/sdk.md](reference/sdk.md)
17
- - **Run and drive the app** - dev server, screenshot the 800x480 screen, press
18
- the physical controls (locally, then over CDP on the device):
8
+ - Calling the daemon, from now-playing to networking, plus every surface the SDK
9
+ ships: [reference/sdk.md](reference/sdk.md)
10
+ - Running the app, screenshotting the 800x480 screen, and pressing the physical
11
+ controls locally and over CDP on the device:
19
12
  [reference/develop.md](reference/develop.md)
20
- - **Install and share** - build, push onto a connected Car Thing, package a zip
21
- anyone can install, and keep the device on the latest bridgething release:
22
- [reference/ship.md](reference/ship.md)
13
+ - Installing onto a connected Car Thing, packaging a zip, and updating the
14
+ device: [reference/ship.md](reference/ship.md)
15
+ - The desktop-side Deno extension, its `ctx` contract, and its permission model,
16
+ when the project has an `extension/` directory:
17
+ [reference/extension.md](reference/extension.md)
23
18
 
24
- The device shape, the control-to-event mapping, and the hard constraints live in
25
- CLAUDE.md, which is always loaded. This skill is the how-to on top of it.
19
+ CLAUDE.md holds the device shape, the control-to-event mapping, and the manifest
20
+ fields.