# Create and publish an Amoosed mode site

## Integrate an existing host

After installing the compiler, run `amw export-runtime ./amw-routes` to copy the version-matched boot page, scripts, stylesheet, service worker, and download helper into a new folder. `route-contract.json` lists their expected paths, SHA-256 hashes, service-worker scope, rewrite targets, and security/cache headers. Deploy the five files at their exact `/amoosed.com/` paths on the **same HTTPS origin** as the original website. Configure `/amoosed.com/app`, `/amoosed.com/app/`, and `/amoosed.com/app/*` to return the boot HTML on cold visits, with the listed CSP. Preserve the original site's other routes and media behavior. Deploy the compiler's carrier overlay at its existing binary file paths; do not publish loose app sources or private keys.

Before release, run `amw check-host https://your-site.example/ [key.amwkey|index.ico]`. It reads the published routes and index, tests favicon and carrier ranges/cache headers, and downloads public resources into temporary verified files. A supplied member key through `AMW_MEMBER_KEY_FILE` or `AMW_CONTENT_KEY_HEX` also checks protected resources. The command reports route/carrier-specific failures and exits nonzero when a check fails. It does not change the host. It cannot test a browser's service-worker registration, gameplay UI, CDN transcoding of unused cover bytes, or publisher authenticity; finish with a browser smoke test. For a local preview, `amw serve BUILT_SITE` provides the required routes and headers on localhost.

## Quick start

1. Install Node.js 22 or newer, then run `npm install -g amoosedweb-compiler`. On Windows x64 with .NET 10, `dotnet tool install --global AmoosedWeb.Compiler` provides the same `amw` command without a separate Node.js installation.
2. Run `amw init my-site`. It creates an independent Git repository with private `.amw/` keys ignored, plus matching Codex and Claude skills for building, maintaining, and publishing the site. The `amoosedweb-cli` npm package remains available as a compatibility shim; new projects should install `amoosedweb-compiler` directly.
3. In `my-site/`, run `build.cmd` on Windows or `sh build.sh` on macOS/Linux. The helper creates and verifies a fresh `builds/local-NNNN/` folder. Run `amw serve builds/local-0001` using the printed path, open the local address, then use the extension's moose icon to enter Amoosed mode.
4. Replace the generated examples with your own content and rebuild to a **new** output directory. Publish the output directory's contents to an HTTPS origin.

For a quick private file share, run `amw init-share game-share game.zip readme.pdf` instead of `init`. The normal page stays generic and does not link the carrier images, so an ordinary page visit does not fetch them. The carrier URLs remain publicly reachable if known; the key controls decoding rather than HTTP access. The Amoosed app lists the original filenames, exact byte sizes, and verified Download links. Input bytes are copied to opaque `.bin` app resources and spread across image carriers targeting about 16 MiB each. The starter uses an external index: send a friend the generated `.amwkey` or ICO after building, or create a private QR with `amw key-link` for the final HTTPS URL. The key is transferable. Each resource is currently limited to 1 GiB and this starter accepts 4 GiB total; browsers with a streaming save picker write and verify incrementally, while the 64 MiB fallback buffers one download, so test large game archives on target devices. The generated `README.txt` explains editing the list and publishing with the same scripts.

The worker limits ordinary app resources to 64 MiB and total automatic boot preparation to 64 MiB. Files explicitly marked as downloads retain the 1 GiB per-resource limit and stream verified parts through the site-owned download helper. Chrome's save picker aborts a failed stream before committing its temporary file; browsers without a streaming picker use a strict 64 MiB Blob fallback. The generated runtime applies a same-origin script/style CSP and denies cross-origin framing. Keep app scripts and styles in the site build; a custom host must reproduce the boot and fallback response headers. Apps requiring remote or inline executable content need a reviewed CSP and runtime integration plan rather than a blanket policy removal.

For Cloudflare Pages Direct Upload, the generated project has guided scripts. Run the commands for your operating system from inside `my-site/`:

```text
release.cmd YOUR_PAGES_PROJECT          # Windows: package only
publish.cmd YOUR_PAGES_PROJECT          # Windows: package and deploy
sh release.sh YOUR_PAGES_PROJECT        # macOS/Linux: package only
sh publish.sh YOUR_PAGES_PROJECT        # macOS/Linux: package and deploy
```

The scripts locate `amw.cjs` in the project or parent folder or use an installed `amw` command. Set `AMW_CLI` to another compiler path if needed. Each run chooses a new numbered output folder. `publish` lists Cloudflare Pages projects, opens Wrangler login if listing fails, offers to create the project, and deploys the verified `pages/` folder on the current Git branch. Pass an existing production branch as the last argument when it differs. Configure the custom domain in the Cloudflare Pages dashboard. For a manual release, the compiler can create a distribution and owner instructions in one step:

The generated helper uses `npx wrangler` and asks the user to confirm whether the named project appears in Wrangler's list; it does not parse project identity automatically. A listing failure currently leads to a login attempt, even if the first failure has another cause. Check the displayed error before continuing. Project creation and Pages deployment do not set registrar nameservers, DNS records, or Pages custom domains. Verify the actual domain separately; a working `*.pages.dev` URL does not establish that apex or `www` DNS and HTTPS reach the correct Pages project.

```text
amw package-pages my-site my-site/distribution YOUR_PAGES_PROJECT
amw verify-managed my-site/distribution
amw deploy-pages my-site/distribution YOUR_PAGES_PROJECT
```

The result is `my-site/distribution/pages/` for upload, `DEPLOY.txt` for the owner, and `MANAGED-FILES.json` listing hashes of every generated file. The build saves a matching private source-and-key snapshot under `my-site/.amw/release-snapshots/` and writes a local `BACKUP-RECEIPT.json` beside `pages/`. Set `AMW_RELEASE_BACKUP_DIR` to an absolute path on another protected local disk if needed. `amw verify-backup my-site/distribution` checks the copy. `deploy-pages` checks both the published files and backup before invoking Wrangler; it requires your Cloudflare login and existing Pages project. The tool leaves `.amw/` keys, member credentials, external index credentials, and the backup outside `pages/`. It never deploys during the build. Use a fresh distribution path for the next release. The snapshot contains bearer keys and is not encrypted by the compiler; make an encrypted offline copy for durable recovery. [Cloudflare's Direct Upload guide](https://developers.cloudflare.com/pages/get-started/direct-upload/) documents the Wrangler flow and limits.

After updating the installed compiler, commit or stash changes in the project Git repository and run `amw update-project my-site`. It refuses a dirty working tree and verifies that `.amw/keys/` is ignored. The tracked `.amw-template.json` records starter file hashes; unchanged starter files can be replaced by newer templates, while owner-edited files are preserved and listed. Review the diff and commit it. Then package to a new distribution directory. Treat `public/` and `distribution/pages/` as compiler-managed: never patch carrier bytes, favicon indexes, service-worker files, or hosting rules in place. Verify the managed manifest before deployment.

The generated project is deliberately small:

| Path | Role |
| --- | --- |
| `site/` | Ordinary site build, including `favicon.ico` and existing media. |
| `app/` | Public Hello World app and an encrypted `members/` example; accepts HTML, CSS, JavaScript, images, fonts, WASM, and downloads. |
| `document.json` | Limited bootstrap document and visible metadata. |
| `bundle.json` | Carrier paths, chunk size, and optional protection rules. |
| `README.txt` | Exact first-build, local preview, key-sharing, and rotation instructions. |
| `AGENTS.md`, `CLAUDE.md`, `.codex/skills/`, `.claude/skills/` | Project guidance and version-matched skills included with the starter. |
| `.amw-template.json` | Compiler-owned, Git-tracked template upgrade record; do not hand-edit. |
| `.amw/keys/` | Private generated content keys; ignored by Git and excluded from `public/`. |

The default `bundle.json` selects `media/scene.png`. Add paths of **existing binary files** in the order you want to use them. A short verified index is appended to `favicon.ico`; payload chunks use the selected carrier mode. A string path uses universal append. An object with `png-chunk` places app bytes in a PNG ancillary chunk before IEND; `mp4-uuid` places them in an MP4 UUID box. Those modes retain browser byte ranges. `{ "path": "media/photo.png", "mode": "png-pixels" }` puts encoded shards into opaque RGB low bits of a PNG; the browser fetches and decodes the whole image. `{ "path": "media/art.wav", "mode": "wav-tones" }` mixes repeated ciphertext packets into a PCM soundtrack; the browser fetches and demodulates the whole WAV. `{ "path": "media/frame.png", "mode": "frame-luma" }` scatters one shard of at most 21 bytes over texture-selected PNG pixels, changing selected red values by at most one level and repeating bits three times. The WAV cover is rewritten as 16 kHz mono 8-bit PCM and holds at most 4 KiB; keep another carrier for the app favicon and larger resources. Image optimization, resizing, audio conversion, or color correction can destroy these modes. `frame-luma` is an image-frame carrier, not MP4/WebM playback extraction. Keep the original files and filenames in `site/`, and rebuild embedded carriers only from those originals. The compiler copies and overlays them in `public/`, verifies hashes, and never copies loose `app/` files there. `public/` contains the site-owned `/amoosed.com/` runtime files because an ordinary browser requires an origin-owned service worker and boot route to execute full HTML, CSS, and JavaScript. This runtime is separate from the alternative app payload.

To keep the index off the ordinary website, set `"indexDelivery":"external"` in `bundle.json`. `build-project` leaves the original `public/favicon.ico` unchanged, encrypts the full app index inside the first selected carrier, and writes `my-site/.amw/indexes/key-<digest>.amwkey` plus the compatible `favicon-<digest>.ico` for the owner to share by email or another channel. It prints both paths. The compact `.amwkey` is a dedicated key file; the recipient does not need the ICO. A random index key is generated on the first build in `my-site/.amw/keys/index.hex` and reused; `AMW_INDEX_KEY_HEX` can supply it in CI without writing a key file. Neither key file nor `.amw/` is copied into `public/`. Back them up securely. Recipients open the ordinary site, use the extension panel's **Open a shared Amoosed key file** action, and select either file on the site's boot page. The runtime checks that the encrypted index and carrier bytes match before loading. Later visits on that browser can reuse the imported credential stored for that site origin. The ordinary site's favicon does not reveal the private index.

The email can present the `.amwkey` or `.ico` alongside a design document, project brief, or question, so the access file fits an ordinary customer exchange. Deliver the file intact; renaming it to `.pdf` or changing its bytes does not turn it into a document. Tell recipients which site to visit and that the attachment opens its Amoosed edition. Treat the attachment as a **bearer key**: forwarding it gives the recipient the same access. For a paid edition, send it only after payment or approval. This is manual distribution, not a checkout, account, subscription, or per-customer licensing system.

The shared favicon file opens the **whole** externally indexed app. If some pages should remain exclusive to members who have that file, set `"protected":["members/"]` and distribute the separate `AMW_CONTENT_KEY_HEX` key only to those members. The index key and member key can be delivered in separate messages or channels. Either shared key can be forwarded, and neither identifies an individual customer. Rotate a key by publishing a new matching carrier build and sending its new key only to continuing recipients; previously downloaded content and complete old snapshots cannot be recalled. See [ENTITLEMENTS.md](ENTITLEMENTS.md).

For a scannable invitation, use `amw key-link my-site/.amw/indexes/key-<digest>.amwkey https://your-site.example/ invitation.svg` after the site origin is known. The command prints an unlock URL and writes an SVG QR code; both carry the same index key and relative locator as either key file. The URL uses the site's HTTPS boot route with an `#amw-index=` fragment. Opening it validates the key against the encrypted index and current carrier bytes, then saves the compact token in that site's browser storage and opens the app. The extension can recognize the resulting verified tab and display its mode controls, but cannot automatically intercept an arbitrary custom URI or open its side panel without Chrome's permitted user action. A QR scanner must open the link in a browser with the Amoosed runtime available; mobile Chrome does not install this desktop extension, though the site-owned boot route can still run in a compatible browser.

For member-only resources, `build-project` also writes `my-site/.amw/keys/<keyId>.amwmember` beside its owner-held hex key, outside `public/`. A standalone bundle owner can export the same file with `amw member-file KEY_ID KEY.hex member.amwmember`. Share the file privately for import on the site's member unlock card, or create a link and QR with `amw member-link member.amwmember https://your-site.example /amoosed.com/app/members/index.html member.svg`. The boot route checks the file's edition ID and verifies the key against encrypted content before saving it. The protected path must exist in the verified app index. A member of an externally indexed app must also receive/import its distinct index key. Keep both key forms, member QR images, and bearer URLs outside the public build; anyone who gets a copy can use the shared key.

An event poster or business card is appropriate when access is intended for everyone who can see or photograph the QR. Keep private or paid QR images and links out of public pages, social posts, and analytics. Anyone who copies the URL can unlock the same release. The token itself contains **no origin**; the HTTPS URL supplies the destination, and the browser stores the verified token under that site's origin. The boot script removes the fragment from the visible URL immediately, but a scanner app, browser history or sync, clipboard, screenshot, or same-origin script may still see it. The fragment is not sent in the HTTP request to the site. Test the printed link and QR against the deployed site before printing materials.

For a standalone overlay, set the same config option and run `amw bundle bundle.json SITE_BUILD APP_BUILD OVERLAY KEY_OUT.amwkey` with `AMW_INDEX_KEY_HEX` set. `OVERLAY` then contains only modified data carriers, and the dedicated key file is the only exported credential. Run `amw verify-bundle OVERLAY KEY_OUT.amwkey`, `amw verify-site MERGED_SITE KEY_OUT.amwkey`, or `amw unpack-bundle OVERLAY RECOVERED_APP KEY_OUT.amwkey`. A `.ico` output remains supported if needed. Keep either key file outside the overlay and public site. This profile is separate from `"protected"`: an external index key opens the whole Amoosed app, while the optional members key still protects selected resources within it.

## Add this to an existing website

Build or export the existing website into `my-site/site/`. Do not replace its normal `index.html` unless intended; preserve its favicon and media paths. Put the alternative app build into `my-site/app/`, adjust `document.json`, and list the carrier paths in `bundle.json`. Run `build-project` and deploy the merged `public/` output. This modifies only the selected carrier bytes, adds the `/amoosed.com/` runtime route and hosting rules, and leaves ordinary pages and content readable by browsers without the extension.

Cloudflare Pages can serve the generated static output. Merge `_redirects` and `_headers` with existing rules, ensuring that `/amoosed.com/app/*` reaches `/amoosed.com/boot.html` on a cold visit. Serve carrier bytes without image recompression, CDN image transformations, or appended-data stripping; support HTTP range requests for large carriers. Confirm the deployed favicon and carrier hashes with `amw verify-site public` before upload and again against downloaded production copies if your host transforms media. A cache or optimizer that changes appended bytes breaks the alternative app. See [WEBAPP.md](WEBAPP.md) and [FORMAT.md](FORMAT.md).

For an existing site that cannot deploy the generated static `public/` folder directly, use `amw bundle bundle.json SITE_BUILD APP_BUILD OVERLAY` to create modified carriers for the site's existing asset URLs. The site owner must arrange same-origin `/amoosed.com/` boot and worker routes through the host's own routing or static-file facilities. Keep the original files as backups, preserve carrier bytes and HTTP range behavior, and check for CDN or image transformations. The compiler does not change a running website. The published CLI does not currently export a generic runtime-route adapter for arbitrary servers; see the route contract in [WEBAPP.md](WEBAPP.md) before choosing this integration.

Before enabling a confidential edition on an existing site, audit **all** JavaScript executing at that site's origin, including CMS plugins and third-party scripts. Same-origin scripts can read the imported index token or use a stored member decryption key; the `/amoosed.com/` path and extension side panel do not isolate keys from the ordinary site's code. If that code cannot be trusted, host the protected experience on a separately controlled origin or postpone confidential access. The current same-origin runtime does not supply that separate-origin deployment automatically.

## Protected resources

The template already has `"keyId": "hello-members"`, `"protected": ["members/"]`, and `app/members/index.html`. On its first successful `build-project`, the compiler generates a random 256-bit key and writes its 64 hexadecimal characters to `my-site/.amw/keys/hello-members.hex` with owner-only file permissions where supported. It prints the **path**, never the key. Back up that file and share its contents privately with members. Later builds reuse it and produce identical carrier bytes when all other inputs are unchanged. The key is outside `public/`, and `.gitignore` excludes `.amw/`. Use `amw rotate-project my-site members` to issue a new member key and ID without rotating the site-wide key, then build to a fresh output folder and share the new `.amwmember`. An automated build can set `AMW_CONTENT_KEY_HEX` instead; when supplied, it is used without writing a key file, and a mismatch with an existing saved key is rejected. See [ROTATION.md](ROTATION.md) for site-only and combined rotation and deployment steps.

For your own project, add `"keyId": "my-edition"` and `"protected": ["members/"]` to `bundle.json` and place protected files under `app/members/`. Keep the entry app public if you want a public landing page. The key is never stored in the carrier files or publication output. Users enter it via the extension's Advanced controls or a private boot URL fragment. A shared key cannot support individual revocation or stop a member copying decrypted content. See [ENTITLEMENTS.md](ENTITLEMENTS.md).

## Compiler packages and .NET direction

Install `amoosedweb-compiler` from npm on macOS, Linux, or Windows, or install the `AmoosedWeb.Compiler` .NET tool on Windows x64 with .NET 10. Both provide the `amw` command. The `amoosedweb-reader` npm package and `AmoosedWeb.Reader` NuGet package provide verified reading APIs. The starter and its generated skills use these published packages and do not require this project's private source repository.

A .NET reader facade lives under `native/`. It calls the reference native `amw` CLI for listing and verified downloads instead of duplicating all carrier, hash, encryption, and index codecs in C#. `AmoosedWeb.Reader` depends on the matching `AmoosedWeb.Native` NuGet package, which supplies the Windows x64 executable. The separate `AmoosedWeb.Compiler` NuGet package is an installable tool. See the human-readable [NuGet installation guide](https://amoosed.com/dotnet.html) for the commands, C# example, and distribution limits. A wholly managed .NET compiler remains a separate possible project, not the current implementation.
