fuzzyworld

fuzzyworld-tools / files / docs / apps.md

apps.md

Blame: the commit that last changed each line · file · history

bb7e1f57 2026-11-06 Pavel Safronov1# Apps (apps.fuzzyworld.net)
2
3Each app lives at `apps.fuzzyworld.net/<app>/` and is a static build uploaded by `fw deploy`.
4
5## Making a repo deploy as an app
6
7Add to the app repo's `package.json`:
8
9```jsonc
10"scripts": { "deploy": "fw deploy" },
11"fuzzyworld": {
12 "app": "my-game", // URL: apps.fuzzyworld.net/my-game/ (required)
13 "title": "My Game", // apps index
14 "description": "One line.", // apps index
15 "repo": "my-game", // DreamHost repo name, if different from app
16 "prebuild": ["pnpm gen-assets"], // commands before checks and build
17 "checks": ["typecheck", "test"], // scripts that must pass (default: whichever of typecheck/lint/test exist)
18 "build": "make public", // default: `<pm> run build`
19 "out": "dist", // default: dist, else public, else build
20 "keep": ["my-game.apk"], // files on the server a deploy must not delete or replace (e.g. a download built elsewhere)
21 "extra": ["sim/*.js"], // build-output files every later deploy keeps: uploaded and updated, never deleted (e.g. old rules versions)
22 "replay": "replay.html?report={record}" // a page of this app that plays a bug report's run record (see issues.md)
23},
24"devDependencies": { "fuzzyworld-tools": "git+https://code.fuzzyworld.net/fuzzyworld-tools.git#semver:^1.0.0" }
25```
26
27For vite, add the plugin. It sets `base` to `/<app>/` for builds (the dev server is unchanged). `FW_APP`, set by
28`fw deploy --as`, overrides the app name.
29
30```ts
31import fuzzyworld from 'fuzzyworld-tools/vite';
32export default defineConfig({ plugins: [fuzzyworld()] });
33```
34
35## `fw deploy`
36
37Run it with `pnpm run deploy` or `npm run deploy`.
38
391. **Clone.** Clones branch `main` of `dh:git/<repo>.git` into a temp dir. It builds what is pushed, never your working copy (`--ref <branch>` for another branch, `--here` to build the current directory as is).
402. **Install** with the lockfile's package manager (`pnpm install --frozen-lockfile`, `npm ci`, `yarn install --frozen-lockfile`).
413. **Prebuild, checks, build.** Any failure stops the deploy.
424. **Check the output.** Every same-site URL in `index.html`, the web manifest's `id`/`scope`/`start_url`, and every `serviceWorker.register(...)` script and scope must stay inside `/<app>/`. That keeps apps on the shared origin from capturing each other, and makes each one install separately on Android. Any problem stops the deploy.
435. **Upload.** `rsync --delete` to `apps.fuzzyworld.net/<app>/`.
44 - `keep` paths are excluded.
45 - `extra` files are protected from `--delete` by an rsync filter: uploaded and updated, never removed.
46 - It writes `.fuzzyworld.json` (commit, time, and the `replay` template; not web-readable).
47 - It refreshes the apps index and the repo's code page.
486. **Print the URL.**
49
50`--dry-run` does everything except upload.
51
52`--as NAME` publishes the app at `apps.fuzzyworld.net/NAME/` instead: a second copy of the same repo (for example
53`explodorama-next` built from `main` while `/explodorama/` is deployed from a tag with `--ref`). The build gets
54`FW_APP=NAME`, which the vite plugin uses for `base`, and the index title gets a suffix.
55
56## The apps index
57
58A table ordered by the newest commit of each app's repo (not by deploy date: an app can be redeployed often
59without its code changing, so the deploy date has its own column).
60
61Columns: screenshot thumbnail (if the runner has taken one), name, description, last commit, deployed, and a source
62link for apps from public repos. The code index on code.fuzzyworld.net is likewise a table of public repos.
63
64Apps hosted elsewhere are listed from `server/site-apps/extra.json` (today: engye on Cloudflare Pages;
65`apps.fuzzyworld.net/engye/...` redirects there).
66
67## Screenshots
68
69After a successful pipeline on the default branch, an app is built the way `fw deploy` builds it, served at
70`/<app>/` inside a Playwright container with no network, and photographed. The pictures go to
71`apps.fuzzyworld.net/_shots/<app>/` and appear on the apps index and the repo's summary page. They need a runner
72with the `chrome` tag ([ci.md](ci.md#tags)).
73
74```jsonc
75"fuzzyworld": {
76 "screenshots": [{ "path": "", "size": "phone", "wait": 1500 }, { "path": "?demo", "size": "desktop" }],
77 // sizes: phone 390×844, tablet 820×1180, desktop 1280×800. Default: one phone shot of the start page.
78 // or a command that writes its own PNGs to $FW_SHOTS_DIR, for apps that need clicks first:
79 // "screenshots": "pnpm shots",
80 // or false: no screenshots
81}
82```
83
84Without runner screenshots, the images in a public repo's `screenshots/` folder are shown instead.