1
0

feat: a bare URL opens on FiDi, not on 1,551 km of tan

One California is the product; the first frame is still the coarsest
pose the pack owns, because createScene opens on chapters[0] and the
state tour starts there. Capture and ?city=california keep that.
A visitor typing tera.lumbridgecorp.com gets openingChapter fidi —
a city they can read — without reordering the pack.
This commit is contained in:
2026-08-24 22:20:22 -07:00
parent 019ff33148
commit 4f4169edc1
4 changed files with 43 additions and 9 deletions
+24 -6
View File
@@ -459,6 +459,18 @@ export interface SceneOptions {
* `stage.setScene(handle.stageScene)` that presents it. * `stage.setScene(handle.stageScene)` that presents it.
*/ */
present?: boolean; present?: boolean;
/**
* Which chapter the camera opens on. Defaults to `chapters[0]`.
*
* The pack's chapter list is a numbered tour and a capture contract — index
* 0 is the state's whole-board pose, and twenty-nine shot-list guards aim at
* buttons by that order. The *visitor* landing is a different question: a
* bare tera.lumbridgecorp.com should open on a city you can read, not on
* 1,551 km of tan. Passing `fidi` here does that without reordering the pack.
* Unknown ids throw rather than silently falling back, so a renamed chapter
* cannot photograph the state under a caption about downtown.
*/
openingChapter?: string;
} }
export interface SceneHandle { export interface SceneHandle {
@@ -1419,8 +1431,14 @@ export async function createScene(
const chapterById = Object.fromEntries(city.chapters.map((c) => [c.id, c])); const chapterById = Object.fromEntries(city.chapters.map((c) => [c.id, c]));
const first = city.chapters[0]; const first = city.chapters[0];
if (!first) throw new Error(`City "${city.id}" declares no chapters`); if (!first) throw new Error(`City "${city.id}" declares no chapters`);
if (options.openingChapter !== undefined && chapterById[options.openingChapter] === undefined) {
throw new Error(
`openingChapter "${options.openingChapter}" is not a chapter of city "${city.id}"`,
);
}
const landing = chapterById[options.openingChapter ?? first.id] ?? first;
let currentChapter = first.id; let currentChapter = landing.id;
const chapterListeners: ((id: string) => void)[] = []; const chapterListeners: ((id: string) => void)[] = [];
const controlModeListeners: ((mode: CityControlMode) => void)[] = []; const controlModeListeners: ((mode: CityControlMode) => void)[] = [];
@@ -1518,10 +1536,10 @@ export async function createScene(
* Two rules govern everything below and both were learned from a picture. * Two rules govern everything below and both were learned from a picture.
* *
* **The board settles exactly where the pack said it would.** `openingPose` * **The board settles exactly where the pack said it would.** `openingPose`
* is `chapterPose(first)` unchanged, so the resting frame is the one the pack * is `chapterPose(landing)` — `chapters[0]` unless the caller named a
* authored, chapter 01 keeps meaning what it says, and a capture of this * chapter, so a capture that does not pass `openingChapter` is the same
* board is the same capture it was before an arrival existed. The wow is the * capture it was, and a bare URL that does can land on a city without
* *approach*; nothing about the destination is second-guessed here. * reordering the pack. The wow is the *approach*.
* *
* **Under `prefers-reduced-motion` there is no move at all.** Not a shorter * **Under `prefers-reduced-motion` there is no move at all.** Not a shorter
* one — none: the camera is placed on the resting pose and that is the whole * one — none: the camera is placed on the resting pose and that is the whole
@@ -1529,7 +1547,7 @@ export async function createScene(
* capture harness honest, because a screenshot of a board mid-flight is a * capture harness honest, because a screenshot of a board mid-flight is a
* screenshot of a different board every time you take it. * screenshot of a different board every time you take it.
*/ */
const openingPose = chapterPose(first); const openingPose = chapterPose(landing);
/** /**
* The opening move, or `null` when there is not one running. * The opening move, or `null` when there is not one running.
+7 -3
View File
@@ -339,9 +339,10 @@ const CITIES: { id: string; label: string; city: City }[] = ONE_CALIFORNIA
/* /*
* With one board there is nothing to choose: the argument above is entirely * With one board there is nothing to choose: the argument above is entirely
* about which of three products a bare URL lands on, and `?one=1` is the answer * about which of three products a bare URL lands on, and `?one=1` is the answer
* that there are not three. The landing *pose* is a separate question and still * that there are not three. The landing *pose* is a separate question: the
* belongs to the chapter list `california-overview` frames the state, and the * pack still opens its chapter list on `california-overview` so capture and
* metro rungs restored in `cities/unify.ts` are how you get down from it. * `?city=california` frame the state, and a bare URL passes `openingChapter:
* "fidi"` so a visitor's first frame is a city they can read.
*/ */
const DEFAULT_CITY_ID = ONE_CALIFORNIA ? "california" : "sf"; const DEFAULT_CITY_ID = ONE_CALIFORNIA ? "california" : "sf";
@@ -1916,6 +1917,9 @@ async function buildBoard(
const drawsMigration = carriesSky && access.feeds?.birds === true; const drawsMigration = carriesSky && access.feeds?.birds === true;
const handle = await createScene(stage, { const handle = await createScene(stage, {
city: entry.city, city: entry.city,
// Bare URL on one California: land in the city, not on 1,551 km of state.
// `?city=california` (and every capture shot) still opens on chapters[0].
...(ONE_CALIFORNIA && CITY_PARAM === null ? { openingChapter: "fidi" } : {}),
// The page's one rig, shared with the office. Handed in rather than built // The page's one rig, shared with the office. Handed in rather than built
// per board; see the note where it is constructed. // per board; see the note where it is constructed.
environment, environment,
+11
View File
@@ -601,6 +601,17 @@ test("the water reflects rather than absorbing, now that there is a sky to refle
const MAIN = readFileSync(path.join(ROOT, "src/main.ts"), "utf8"); const MAIN = readFileSync(path.join(ROOT, "src/main.ts"), "utf8");
test("a bare URL on one California opens on FiDi, not on the whole state", () => {
assert.ok(
MAIN.includes('openingChapter: "fidi"'),
"the visitor landing lost its city; they will see 1,551 km of tan",
);
assert.ok(
MAIN.includes("CITY_PARAM === null"),
"the fidi opening must not apply to ?city=california — that is the capture harness",
);
});
test("main.ts makes exactly one call into the chrome, and writes no visibility itself", () => { test("main.ts makes exactly one call into the chrome, and writes no visibility itself", () => {
const applies = [...MAIN.matchAll(/chrome\?\.apply\(chromeState\(/g)].length; const applies = [...MAIN.matchAll(/chrome\?\.apply\(chromeState\(/g)].length;
assert.equal( assert.equal(
+1
View File
@@ -165,6 +165,7 @@ describe("one California's chapters", () => {
// Nothing merged twice, which a naive concat of two packs sharing an id // Nothing merged twice, which a naive concat of two packs sharing an id
// would do without failing anything else. // would do without failing anything else.
assert.equal(new Set(ids).size, ids.length); assert.equal(new Set(ids).size, ids.length);
assert.ok(ids.includes("fidi"), "the visitor landing names a chapter the merge dropped");
}); });
it("restates each merged rung in this board's units, keeping its true metres", () => { it("restates each merged rung in this board's units, keeping its true metres", () => {