Skip to content
This repository was archived by the owner on Sep 10, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/getting-started/manual-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ module, and call `runEngineApp` from `lib/main.dart`. The
Dart pieces.

Create `app-config.json` beside `pubspec.yaml` with `API_BASE_URL`,
`GOOGLE_WEB_CLIENT_ID`, optional `APP_HOST`, and the public
`FIREBASE_VAPID_KEY`. Read them once with `const String.fromEnvironment` in
`GOOGLE_WEB_CLIENT_ID`, the optional `APP_HOST` and `AUTH_DOMAIN`, and the
public `FIREBASE_VAPID_KEY`. Read them once with `const String.fromEnvironment` in
`main.dart`, pass them into `EngineConfig`, and use
`--dart-define-from-file=app-config.json` for both Android and web commands.
The complete shape and validation rules are in
Expand Down
6 changes: 6 additions & 0 deletions docs/getting-started/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ notifications and account deletion run on; token verification uses
features fail only when exercised. `wrangler dev` reads `.dev.vars` at startup,
so restart `pnpm dev` afterwards.

**5. Link Google Analytics.** If the console shows _"Google Analytics not
enabled for Project"_, that is expected: a project created through the CLI
during scaffolding is not linked to an Analytics account, and only the console's
own create flow offers it. Firebase Console → Settings → **Integrations** →
Google Analytics → **Enable**.

Steps 2 and 3 are public values compiled into the app. Step 4 is not:
`.dev.vars` is a real credential, is git-ignored, and must stay that way. Delete
the downloaded JSON once you have copied the two fields out of it.
Expand Down
23 changes: 16 additions & 7 deletions docs/ship-it/branding.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,22 @@ mid-download does not lose the page.
the first deploy. What it does *not* have is the legal half: those routes are
not mounted, so the footer carries only the credit until you fill in `operator`.

The page also waits for a Flutter web build to reach `public/` before it shows
your app icon or a "Play on the web" button, because both would otherwise be
broken: the icons ship inside that bundle, and `/` would bounce straight back
to `/download`. Until then it stands the EigenInteractive mark in for the icon,
drawn in your `primaryColor`, exactly as the Flutter shell defaults to the
EigenInteractive seed and credit. Run `pnpm run build:web` and your own icon
replaces it.
The page waits for a Flutter web build to reach `public/` before it offers a
"Play on the web" button, because `/` would otherwise bounce straight back to
`/download`.

Icons are a separate question, and the answer is the same on every page the
engine renders: the browser tab, the download page's logo, and the manifest.
**Until your game has icons of its own, all three use the EigenInteractive
mark**, served by the Worker and drawn in your `primaryColor`, exactly as the
Flutter shell defaults to the EigenInteractive seed and credit. It is a
placeholder, not a default. The moment `favicon.png` exists in `public/` the
engine links your icons everywhere and stops serving its own.

That check looks at the icons themselves rather than at the web build, so a
game with no web build still gets its own. `pnpm run build:web` is the usual
way they arrive; an Android-only game can copy the same files out of `app/web/`
into `public/` and get the identical result.

A game with no web build *and* no store URLs in `deepLink` has nothing to offer
at all, and the page says `Coming soon.` rather than trailing off after the
Expand Down
13 changes: 11 additions & 2 deletions docs/ship-it/configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const apiBaseUrl = String.fromEnvironment('API_BASE_URL');
const googleWebClientId = String.fromEnvironment('GOOGLE_WEB_CLIENT_ID');
const firebaseVapidKey = String.fromEnvironment('FIREBASE_VAPID_KEY');
const appHost = String.fromEnvironment('APP_HOST');
const authDomain = String.fromEnvironment('AUTH_DOMAIN');

await runEngineApp(
module: const RpsModule(),
Expand All @@ -83,6 +84,7 @@ await runEngineApp(
googleWebClientId: googleWebClientId,
firebaseVapidKey: firebaseVapidKey,
appHost: appHost.isEmpty ? null : appHost,
authDomain: authDomain.isEmpty ? null : authDomain,
),
),
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
Expand All @@ -105,6 +107,7 @@ flutter build appbundle --release \
| `API_BASE_URL` | **yes** | Origin of the Worker: scheme + host only, **no path, no trailing slash**. Routes carry their own `/api/engine` prefix; the socket is this origin with `ws`/`wss`. |
| `GOOGLE_WEB_CLIENT_ID` | yes | Google Sign-In. Both platforms use the *web* client, so an Android-only app still needs it. |
| `APP_HOST` | optional | This game's hostname, without scheme. In the default deployment it is the host part of `API_BASE_URL`; it enables invite/replay sharing and legal links. `/download` is the native install page. |
| `AUTH_DOMAIN` | optional | Firebase Auth's own domain, without scheme, overriding the project default. Cosmetic and web-only: it is the hostname Google's account chooser names during sign-in. **Not `APP_HOST`**; it must be a Firebase Hosting domain. See [Deploy the web app](./deploy-the-web-app.md#the-hostname-players-see-when-they-sign-in). |
| `FIREBASE_VAPID_KEY` | **yes for web** | Public FCM Web Push key from the same Firebase project. An empty key is a web startup configuration error. Android does not consume it. |

These values are embedded in the Android binary or downloaded web bundle and
Expand All @@ -124,6 +127,7 @@ empty strings. What it leaves is what no CLI can produce.
| `GOOGLE_WEB_CLIENT_ID` | filled in after `firebase:configure`, when there is one to copy | Firebase Console → Authentication → Sign-in method → Google → **Web SDK configuration**. It is also the `"client_type": 3` entry of `app/android/app/google-services.json`. |
| `FIREBASE_VAPID_KEY` | empty | Firebase Console → Project settings → **Cloud Messaging** → Web configuration, **Generate key pair** if the list is empty. Web Push certificates are not served by the Firebase CLI, so this is always a manual copy. |
| `APP_HOST` | empty | Your hostname once you have one. Leave it empty locally; sharing links are simply off. |
| `AUTH_DOMAIN` | empty | Nothing to get, and most games never set it. Empty means sign-in uses the Firebase project's own domain, which works everywhere. |

An empty `GOOGLE_WEB_CLIENT_ID` after a successful `firebase:configure` means
one thing: **the Google sign-in provider was never enabled**. Firebase creates
Expand Down Expand Up @@ -160,8 +164,13 @@ Firebase is mandatory on the client. A fresh scaffold contains a throwing
`firebase_options.dart` seam so analysis works before project setup, but the app
will not start until FlutterFire replaces it with real platform configuration.

1. **Create the project** at console.firebase.google.com with Analytics enabled,
or let step 2 do it: the first run offers to.
1. **Create the project**, either at console.firebase.google.com or by letting
step 2 do it: the first run offers to. The two differ in one respect. Only
the console's create flow links a Google Analytics account, so a project
created through the CLI reports *"Google Analytics not enabled for Project"*
and the engine's automatic events have nowhere to land. Link one afterwards
under Settings → Integrations → Google Analytics. Crashlytics reports either
way.
2. Install and authenticate the official tooling:

```bash
Expand Down
43 changes: 43 additions & 0 deletions docs/ship-it/deploy-the-web-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,49 @@ The combined deploy removes the usual ordering race for web. Android still
needs version ordering: publish a compatible Play build before server behavior
that requires it.

### The hostname players see when they sign in

On the web, sign-in runs through Firebase's popup, which loads
`https://<authDomain>/__/auth/handler`, and Google's account chooser names that
host. By default it reads:

> Sign in to continue to **my-project.firebaseapp.com**

**This is fine, and most games should leave it alone.** It is cosmetic, it does
not change what sign-in does, and Android never shows it, because the native
Google flow is used there instead.

If you do want your own name on that screen, it is two independent changes and
either works without the other:

| To change | Where | Needs a domain |
|---|---|---|
| The product name and logo | Google Cloud Console → APIs & Services → OAuth consent screen | No |
| The hostname in the sentence | `AUTH_DOMAIN` in `app-config.json` | Yes |

The consent-screen half is the cheaper win and needs no configuration at all.

The hostname half needs a domain **Firebase Hosting** answers for, because that
is what serves `/__/auth/handler`. It cannot be `APP_HOST`: that name is your
Worker. The two are siblings, `auth.rps.example.com` beside `rps.example.com`.
Add the custom domain under Hosting in the Firebase console, add it under
Identity Platform → Identity providers → Project settings → Add Domain, then
set it:

```json
{
"APP_HOST": "rps.example.com",
"AUTH_DOMAIN": "auth.rps.example.com"
}
```

Leave `AUTH_DOMAIN` empty and the app uses the project's own domain, which is
the scaffold's state and needs no Firebase Hosting at all. The engine applies
the value at startup rather than expecting you to edit `firebase_options.dart`,
which is generated and would lose the edit on the next
`pnpm firebase:configure`. A value Firebase Hosting does not answer for breaks
web sign-in outright, so set it once the domain resolves, not before.

### Deliberately splitting the origins

A separate static host remains supported. Point `API_BASE_URL` at the Worker,
Expand Down
27 changes: 20 additions & 7 deletions docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,16 +388,29 @@ const config: Config = {
},
{ to: "/showcase", label: "Showcase", position: "left" },
{ to: "/blog", label: "Changelog", position: "left" },
// Renders as "0.3.x", the label from `versions.current` above. With
// one version live the dropdown exists to answer "which engine is this
// describing, and what Flutter release pairs with it", which is why the
// compatibility table is pinned into it rather than left in the
// sidebar alone. Once a version is cut it becomes an ordinary version
// switcher and the extra item stays useful.
// Renders as "0.3.x", the label from `versions.current` above. With one
// version live it exists to answer "which engine is this describing",
// and it becomes an ordinary switcher once a version is cut.
//
// Nothing is pinned in via `dropdownItemsAfter`, and the compatibility
// table specifically must not be. Each version entry links to *the doc
// you are currently reading* in that version, so on a versioned page the
// entry is a self-link; adding a versioned doc to the dropdown makes the
// two collide on that doc's own page, where both render with
// `dropdown__link--active` pointing at the same href. Docusaurus' own
// example pins `/versions`, a page outside `/docs` that no version owns,
// which is the case this option is for. Compatibility lives in
// `referenceSidebar` and is reachable there.
//
// `dropdownActiveClassDisabled` because each version entry links to the
// doc you are currently reading, which makes it a self-link on every
// docs page and so permanently "active". Highlighting it says nothing:
// with one version there is no other state it could be in. Docusaurus'
// own example sets this for the same reason.
{
type: "docsVersionDropdown",
position: "right",
dropdownItemsAfter: [{ to: "/docs/reference/compatibility", label: "Compatibility" }],
dropdownActiveClassDisabled: true,
},
{
href: GITHUB,
Expand Down