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:
+24
-6
@@ -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
@@ -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,
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user