diff --git a/.github/coverage-ratchet.json b/.github/coverage-ratchet.json
index c9f47009662..59d9a9b9d78 100644
--- a/.github/coverage-ratchet.json
+++ b/.github/coverage-ratchet.json
@@ -62,7 +62,7 @@
"site/packaged-object-runtime.mts",
"site/model/planetary-system-members.mts",
"site/prepare-body-moons.mts",
- "site/prepared-arrival.mts",
+ "site/navigation/prepared-arrival.mts",
"site/navigation/prepared-descriptor.mts",
"site/prepared/prepared-object-path.mts",
"site/content/prepared-panel-content.mts",
@@ -410,7 +410,7 @@
"branches": 87.5,
"functions": 91.6
},
- "site/prepared-arrival.mts": {
+ "site/navigation/prepared-arrival.mts": {
"lines": 100,
"branches": 100,
"functions": 100
diff --git a/.github/scripts/checks/object-test-relocation.test.mts b/.github/scripts/checks/object-test-relocation.test.mts
index d2edc12162f..43d12dbcbc6 100644
--- a/.github/scripts/checks/object-test-relocation.test.mts
+++ b/.github/scripts/checks/object-test-relocation.test.mts
@@ -9,7 +9,7 @@ import { discoverObjectTests } from '@cssearth/bake/run-implemented-objects/sour
const root = projectRoot(import.meta.url);
test('per-object discovery keeps shared suites and every body-owned suite collected in root lanes', async () => {
const files = await discoverObjectTests('earth', { projectRoot: root });
- assert.ok(files.includes(resolve(root, 'site/test/runtime-package.test.mts')));
+ assert.ok(files.includes(resolve(root, 'site/world/runtime-package.test.mts')));
assert.ok(files.includes(resolve(root, 'packages/bake/src/raster/raster-pages.test.mts')));
const lanes = testLaneFiles(root, JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8')) as unknown, ['test:packages', 'test:site']);
for (const file of [...lanes.packages, ...lanes.site].filter(file => file.startsWith('src/objects/earth/')))
diff --git a/.github/site-refactor.json b/.github/site-refactor.json
index 30981bb6cc3..35589bc662f 100644
--- a/.github/site-refactor.json
+++ b/.github/site-refactor.json
@@ -1,7 +1,39 @@
{
- "mode": "semantic",
- "moves": {},
- "outputs": [],
- "layout": "changes",
- "change": "S3-1 held address"
+ "mode": "pure-move",
+ "moves": {
+ "site/prepared-arrival.mts": "site/navigation/prepared-arrival.mts",
+ "site/test/body-moons.test.mts": "site/build/prepare/body-moons.test.mts",
+ "site/test/category-frames.test.mts": "site/build/prepare/category-frames.test.mts",
+ "site/test/compact-spectrum.test.mts": "site/overview/compact-spectrum.test.mts",
+ "site/test/moon-labels.test.mts": "site/world/moon-labels.test.mts",
+ "site/test/navigation-ontology.test.mts": "site/world/navigation-ontology.test.mts",
+ "site/test/navigation-preparation.test.mts": "site/world/navigation-preparation.test.mts",
+ "site/test/navigation-request.test.mts": "site/navigation/navigation-request.test.mts",
+ "site/test/navigation-router-context.mts": "site/scene/navigation-router-context.test-support.mts",
+ "site/test/navigation-test-values.mts": "site/navigation/navigation-test-values.test-support.mts",
+ "site/test/nebula-search.test.mts": "site/world/nebula-search.test.mts",
+ "site/test/object-navigation.test.mts": "site/world/object-navigation.test.mts",
+ "site/test/object-package-contract.test.mts": "site/build/object-package-contract.test.mts",
+ "site/test/prepared-arrival.test.mts": "site/navigation/prepared-arrival.test.mts",
+ "site/test/prepared-body-billboards.test.mts": "site/world/prepared-body-billboards.test.mts",
+ "site/test/prepared-icons.test.mts": "site/build/prepare/prepared-icons.test.mts",
+ "site/test/prepared-world-context.test.ts": "site/world/prepared-world-context.test.ts",
+ "site/test/runtime-package.test.mts": "site/world/runtime-package.test.mts",
+ "site/test/satellite-arrival-framing.test.mts": "site/navigation/satellite-arrival-framing.test.mts",
+ "site/test/scene-contract.test.mts": "site/world/scene-contract.test.mts",
+ "site/test/search-api.test.mts": "site/journeys/search-api.test.mts",
+ "site/test/search-response.test.mts": "site/server/search-response.test.mts",
+ "site/test/startup-cover.test.mts": "site/browser/startup-cover.test.mts",
+ "site/test/system-text.test.mts": "site/build/prepare/system-text.test.mts",
+ "site/test/system-view-file.mts": "site/world/system-view-file.test-support.mts",
+ "site/test/world-stars.test.mts": "site/world/world-stars.test.mts",
+ "site/test/world-tables.test.mts": "site/world/world-tables.test.mts",
+ "site/prepared-arrival.characterization.test.mts": "site/navigation/prepared-arrival.characterization.test.mts",
+ "site/object-entry-types.test.mts": "site/directory/object-entry-types.test.mts",
+ "site/moon-catalogue.mts": "site/content/moon-catalogue.mts",
+ "site/moon-catalogue.test.mts": "site/content/moon-catalogue.test.mts",
+ "site/surrounded-body.mts": "site/world/surrounded-body.mts",
+ "site/surrounded-body.test.mts": "site/world/surrounded-body.test.mts"
+ },
+ "change": "S4-2 remaining moves"
}
diff --git a/docs/moon-catalogues.md b/docs/moon-catalogues.md
index 8ddadb13028..68293bd51f8 100644
--- a/docs/moon-catalogues.md
+++ b/docs/moon-catalogues.md
@@ -79,7 +79,7 @@ sequential and cached in `output/moon-horizons/`. Review changes in totals,
identity and ephemeris coverage before accepting refreshed inputs. Do not reuse
cached replies for a different epoch or reference frame.
-Focused checks: `node --test site/test/body-moons.test.mts
-site/test/moon-labels.test.mts site/browser/source-link.test.mts`. They verify full
+Focused checks: `node --test site/build/prepare/body-moons.test.mts
+site/world/moon-labels.test.mts site/browser/source-link.test.mts`. They verify full
catalogue membership, available destinations, major/minor orbit policy, planet
occlusion, caption collision and overview hiding.
diff --git a/docs/navigation-identity.md b/docs/navigation-identity.md
index a6fdaaf633e..0387b540aca 100644
--- a/docs/navigation-identity.md
+++ b/docs/navigation-identity.md
@@ -35,7 +35,7 @@ the body as that object's centre and its radius. A star of the Large Magellanic
zooms out into the Cloud, M87* into M87, M87 into the Virgo Cluster. That scene is
then left the way any body's is ([overview-selection.mts](../site/overview-selection.mts),
[inside-view.mts](../site/inside-view.mts)). The way back in needs no click where the object's walls
-surround a body: its entry names that body (`inner`, [surrounded-body.mts](../site/surrounded-body.mts)), and
+surround a body: its entry names that body (`inner`, [surrounded-body.mts](../site/world/surrounded-body.mts)), and
a zoom in that reaches the nearest view the object's scene allows goes on into the body's scene, which draws
the walls around it. While that body is selected the object has no marker: the view is among its walls, and its
breadcrumb names it ([application-world-context.mts](../site/application-world-context.mts)). The Homunculus Nebula zooms in to Eta Carinae, NGC 2392 to HD 59088. A system can be inside another: a star
@@ -196,7 +196,7 @@ identities. See [object provenance](object-provenance.md) for their lineage.
## Checks
-`site/test/navigation-ontology.test.mts` compares every prepared spatial subject
+`site/world/navigation-ontology.test.mts` compares every prepared spatial subject
with the registry and search, checks every body distance against its prepared
frame, and resolves the actual galaxy references. The bibliography tests reject
conflicting keys and invalid locators. Contribution tests distinguish view
diff --git a/docs/object-discovery.md b/docs/object-discovery.md
index e17ebd5fe37..30a9363eb88 100644
--- a/docs/object-discovery.md
+++ b/docs/object-discovery.md
@@ -241,7 +241,7 @@ Gray placeholders receive the same display cue without invented surface detail.
Measured stellar limb darkening and thermal-map palettes keep their source
treatment. The Earth and Moon browser view
checks the Moon sprite in the existing world renderer.
-`site/test/navigation-preparation.test.mts` checks every registered body marker
+`site/world/navigation-preparation.test.mts` checks every registered body marker
and resolved context image for transparent corners and nonempty content.
The shared recipe tests separately check bright-center, darker-limb shading.
The catalogue audit
diff --git a/docs/page-navigation-transport.md b/docs/page-navigation-transport.md
index 3e4911849f0..1b3b9aac99b 100644
--- a/docs/page-navigation-transport.md
+++ b/docs/page-navigation-transport.md
@@ -204,7 +204,7 @@ After building the packages and renderer, check page metadata with:
node --test site/server/object-page-data.test.mts
pnpm test:packages # includes rendering/prepared-scene-serialization.test.ts
node --test site/journeys/rendered-page.test.mts
-node --test site/test/search-response.test.mts
+node --test site/server/search-response.test.mts
node --test site/server/dataset-response.test.mts site/model/dataset-url.test.mts
node --test site/scene/scene-session.test.mts
```
diff --git a/docs/performance/startup-billboard.md b/docs/performance/startup-billboard.md
index 4659b9af910..7f4c2c12137 100644
--- a/docs/performance/startup-billboard.md
+++ b/docs/performance/startup-billboard.md
@@ -4,7 +4,7 @@ A default object page with a prepared arrival billboard sends that image instead
The shared responsive fit determines the initial silhouette. The camera retains the billboard's baked distance and rotation, adjusting projection scale to fit the viewport. The billboard and detailed scene therefore use the same perspective. Preparation requests the selected viewport texture level and uses the same visible-face demand as the mounted scene; existing low-resolution textures for unseen faces remain an independent resource optimization.
-`site/prepared-arrival.mts` owns the resource lease, viewport texture policy, progressive mount options, camera acknowledgement, cancellation and cover release for startup and navigation. Startup supplies its prepared destination view; fly-to supplies its travelling camera and resumes its existing flight after acknowledgement. Both use the same scene-session activation and camera-acknowledged reveal path. The two modes differ only in camera progression: startup supplies a stationary destination; fly-to runs the existing travel clock.
+`site/navigation/prepared-arrival.mts` owns the resource lease, viewport texture policy, progressive mount options, camera acknowledgement, cancellation and cover release for startup and navigation. Startup supplies its prepared destination view; fly-to supplies its travelling camera and resumes its existing flight after acknowledgement. Both use the same scene-session activation and camera-acknowledged reveal path. The two modes differ only in camera progression: startup supplies a stationary destination; fly-to runs the existing travel clock.
The input surface stays inert through prepared scene activation, whether or not the camera can use a billboard cover. Like a fly-to replacement, startup attaches the shared world before mounting detail. Behind the photograph, startup builds that world and the shell while the first view's images download. On every screen a body first draws its first texture level, then sharpens to the level its size on screen calls for. The world's first frame is planned while the detail activates and paints: as soon as the detail's navigation facts exist, the world selects the body and plans the startup camera the detail already holds (`world-frame-queue.ts` `warm`). The plan is used only by the first request for that identical view while the world's presentation is unchanged, so the detail's connection commits it without planning again and the arrival's camera acknowledgement rides the same frame; any other request, a changed camera or a changed presentation plans as before. A change nobody owns yet (the caption's measurement) follows the committed frame with one more plan, as a refresh during a plan does. Both arrivals reveal at the proven fly-to boundary: activation has finished mounting and painting, and the destination camera publication has been acknowledged. The travel owner positions the cover during flight; attachment holds that image still until reveal. The cover does not subscribe to stage-coordinate camera publications. There is no extra router publication or second reveal gate. Readiness has no fixed delay. An empty stage shows the cold-start ring. When the photograph shows, the ring leaves and the header's progress line runs, the same line a fly-to shows, because the photograph looks like a scene but does not answer input yet. The line stops when the detail presents or the mount fails. It animates only its own transform; reduced motion makes it static. There is no startup coast, fade or second zoom.
diff --git a/docs/site-architecture.md b/docs/site-architecture.md
index 6b057efd18c..4f40e692c70 100644
--- a/docs/site-architecture.md
+++ b/docs/site-architecture.md
@@ -11,30 +11,30 @@ A folder imports itself or strictly lower layers. Sibling folders, including L0
| Tier | Folder | Purpose | Incoming moves |
| ---: | --- | --- | --- |
-| 0 | `browser/` | Browser input, DOM and serialized import queue | 2; `import-queue.mts` |
+| 0 | `browser/` | Browser input, DOM and serialized import queue | 1; `import-queue.mts` |
| 0 | `model/` | Object identities, routes and held addresses | 0 |
-| 0 | `overview/` | Prepared spectral overview readers | 1 |
+| 0 | `overview/` | Prepared spectral overview readers | 0 |
| 0 | `prepared/` | Prepared transports and generated inputs | 23; `prepared-catalogue.d.mts`, `prepared-navigation-markers.d.mts`, `prepared-shell-icons.d.mts`, `prepared-shell-titles.d.mts` |
| 0 | `source/` | Preserved input records and artwork | 0 |
| 0 | `vendor/` | Preserved third-party notices | 0 |
| 0 | `server-assets/` | Server and build prepared-asset origin | 0 |
| 0 | `contracts/` | Shared page and shell interfaces | 0 |
-| 1 | `directory/` | Startup reads and object catalogue directory | 9; `startup-world.mts`, `object-directory.mts`, `objects.mts`, `world-context-plan.mts` |
+| 1 | `directory/` | Startup reads and object catalogue directory | 8; `startup-world.mts`, `object-directory.mts`, `objects.mts`, `world-context-plan.mts` |
| 1 | `minimap/` | Surface-map measurements and view formatting | 0 |
-| 2 | `world/` | Shared framing, visibility and camera context | 52; `world-objects.mts`, `world-system-views.mts`, `stellar-extents.mts`, `hosted-banks.mts` |
-| 3 | `content/` | Card content, citations and metadata | 13; `exploration-catalog.mts`, `source-documentation.mts`, `seo.mts`, `seo-trail.mts` |
-| 3 | `navigation/` | History, requests, flights and arrivals | 10; `prepared-arrival.mts`, `prepared-world-navigation.mts` |
+| 2 | `world/` | Shared framing, visibility and camera context | 40; `world-objects.mts`, `world-system-views.mts`, `stellar-extents.mts`, `hosted-banks.mts` |
+| 3 | `content/` | Card content, citations and metadata | 11; `exploration-catalog.mts`, `source-documentation.mts`, `seo.mts`, `seo-trail.mts` |
+| 3 | `navigation/` | History, requests, flights and arrivals | 4; `prepared-world-navigation.mts` |
| 4 | `search/` | Catalogue search and result presentation | 0 |
| 4 | `selection/` | Committed selection and camera handovers | 8; `scene/scene-selection.mts`, `satellite-selection.mts`, `overview-selection.mts`, `showcase.mts` |
| 5 | `shell/` | Retained shell controls and panels | 14; `object-browser.mts`, `feature-browser.mts`, `destination-browser.mts`, `selection-presentation.mts` |
-| 6 | `server/` | SSR readers, responses and host middleware | 8; `object-entry.mts`, `world-places.mts`, `dot-catalogue-data.mts`, `social-images.mts` |
-| 6 | `scene/` | Scene sessions, replacement and publication | 8; `object-adapter.mts`, `packaged-object-runtime.mts`, `startup-billboard.mts` |
+| 6 | `server/` | SSR readers, responses and host middleware | 7; `object-entry.mts`, `world-places.mts`, `dot-catalogue-data.mts`, `social-images.mts` |
+| 6 | `scene/` | Scene sessions, replacement and publication | 7; `object-adapter.mts`, `packaged-object-runtime.mts`, `startup-billboard.mts` |
| 7 | `startup/` | Page boot helpers and router entry | 5; `shared-imports.mts`, `startup-boot.mts` |
-| 7 | `build/` | Site preparation and packaging | 8; `prepare-body-moons.mts` |
+| 7 | `build/` | Site preparation and packaging | 3; `prepare-body-moons.mts` |
| 8 | `layouts/` | Shared page frame and its styles | 2; `components/ObjectSwatchStyles.astro`, `object-shell.css` |
| 9 | `components/` | Reusable Astro markup and SSR composition | 0 |
| 10 | `pages/` | Routes and object-page entries | 0 |
-| 11 | `journeys/` | Cross-cutting journeys and support | 1 |
+| 11 | `journeys/` | Cross-cutting journeys and support | 0 |
| 11 | `test/` | Retired test folder; no final occupants | 0 |
diff --git a/docs/site-architecture/moves.json b/docs/site-architecture/moves.json
index 27efda59aa9..7b0878fe7d0 100644
--- a/docs/site-architecture/moves.json
+++ b/docs/site-architecture/moves.json
@@ -31,7 +31,6 @@
"site/object-adapter.mts": "site/scene/object-adapter.mts",
"site/packaged-object-runtime.mts": "site/scene/packaged-object-runtime.mts",
"site/startup-billboard.mts": "site/scene/startup-billboard.mts",
- "site/prepared-arrival.mts": "site/navigation/prepared-arrival.mts",
"site/prepared-world-navigation.mts": "site/navigation/prepared-world-navigation.mts",
"site/import-queue.mts": "site/browser/import-queue.mts",
"site/shared-imports.mts": "site/startup/shared-imports.mts",
@@ -63,50 +62,24 @@
"site/navigation/evidence/star-click/one-click.jpg": "site/navigation/evidence/star-click/one-click.jpg",
"site/test/application-world-frames.test.mts": "site/world/application-world-frames.test.mts",
"site/test/application-world-visibility.test.mts": "site/world/application-world-visibility.test.mts",
- "site/test/body-moons.test.mts": "site/build/prepare/body-moons.test.mts",
- "site/test/category-frames.test.mts": "site/build/prepare/category-frames.test.mts",
- "site/test/compact-spectrum.test.mts": "site/overview/compact-spectrum.test.mts",
"site/test/destination-browser.test.mts": "site/shell/destination-browser.test.mts",
"site/test/diagnostic-recorder.test.mts": "site/shell/diagnostic-recorder.test.mts",
"site/test/hosted-banks.test.mts": "site/build/prepare/hosted-banks.test.mts",
"site/test/import-queue.test.mts": "site/startup/import-queue.test.mts",
- "site/test/moon-labels.test.mts": "site/world/moon-labels.test.mts",
"site/test/navigation-history.test.mts": "site/navigation/navigation-history.test.mts",
- "site/test/navigation-ontology.test.mts": "site/world/navigation-ontology.test.mts",
- "site/test/navigation-preparation.test.mts": "site/world/navigation-preparation.test.mts",
- "site/test/navigation-request.test.mts": "site/navigation/navigation-request.test.mts",
- "site/test/navigation-router-context.mts": "site/scene/navigation-router-context.test-support.mts",
"site/test/navigation-scope.test.mts": "site/world/navigation-scope.test.mts",
- "site/test/navigation-test-values.mts": "site/navigation/navigation-test-values.test-support.mts",
- "site/test/nebula-search.test.mts": "site/world/nebula-search.test.mts",
"site/test/object-children.test.mts": "site/content/object-children.test.mts",
"site/test/object-directory.test.mts": "site/directory/object-directory.test.mts",
- "site/test/object-navigation.test.mts": "site/world/object-navigation.test.mts",
- "site/test/object-package-contract.test.mts": "site/build/object-package-contract.test.mts",
"site/test/object-systems.test.mts": "site/world/object-systems.test.mts",
"site/test/overview-selection.test.mts": "site/selection/overview-selection.test.mts",
- "site/test/prepared-arrival.test.mts": "site/navigation/prepared-arrival.test.mts",
- "site/test/prepared-body-billboards.test.mts": "site/world/prepared-body-billboards.test.mts",
- "site/test/prepared-icons.test.mts": "site/build/prepare/prepared-icons.test.mts",
- "site/test/prepared-world-context.test.ts": "site/world/prepared-world-context.test.ts",
"site/test/prepared-world-navigation.test.mts": "site/navigation/prepared-world-navigation.test.mts",
- "site/test/runtime-package.test.mts": "site/world/runtime-package.test.mts",
- "site/test/satellite-arrival-framing.test.mts": "site/navigation/satellite-arrival-framing.test.mts",
"site/test/satellite-systems.test.mts": "site/world/satellite-systems.test.mts",
- "site/test/scene-contract.test.mts": "site/world/scene-contract.test.mts",
- "site/test/search-api.test.mts": "site/journeys/search-api.test.mts",
- "site/test/search-response.test.mts": "site/server/search-response.test.mts",
"site/test/seo.test.mts": "site/content/seo.test.mts",
"site/test/showcase.test.mts": "site/selection/showcase.test.mts",
"site/test/startup-billboard.test.mts": "site/scene/startup-billboard.test.mts",
- "site/test/startup-cover.test.mts": "site/browser/startup-cover.test.mts",
"site/test/stellar-extents.test.mts": "site/world/stellar-extents.test.mts",
"site/test/system-framing.test.mts": "site/world/system-framing.test.mts",
- "site/test/system-text.test.mts": "site/build/prepare/system-text.test.mts",
- "site/test/system-view-file.mts": "site/world/system-view-file.test-support.mts",
"site/test/view-readout.test.mts": "site/shell/view-readout.test.mts",
- "site/test/world-stars.test.mts": "site/world/world-stars.test.mts",
- "site/test/world-tables.test.mts": "site/world/world-tables.test.mts",
"site/test/zoom-scope.test.mts": "site/world/zoom-scope.test.mts",
"site/moon-labels.prepared.json": "site/prepared/moon-labels.prepared.json",
"site/prepared-catalogue.mjs": "site/prepared/prepared-catalogue.mjs",
@@ -151,7 +124,6 @@
"site/inside-view.characterization.test.mts": "site/world/inside-view.characterization.test.mts",
"site/object-systems.characterization.test.mts": "site/world/object-systems.characterization.test.mts",
"site/overview-selection.characterization.test.mts": "site/selection/overview-selection.characterization.test.mts",
- "site/prepared-arrival.characterization.test.mts": "site/navigation/prepared-arrival.characterization.test.mts",
"site/prepared-world-navigation.characterization.test.mts": "site/navigation/prepared-world-navigation.characterization.test.mts",
"site/prepared-world-presentation.characterization.test.mts": "site/world/prepared-world-presentation.characterization.test.mts",
"site/seo.characterization.test.mts": "site/content/seo.characterization.test.mts",
@@ -164,8 +136,5 @@
"site/world-context-plan.characterization.test.mts": "site/directory/world-context-plan.characterization.test.mts",
"site/world-places.characterization.test.mts": "site/server/world-places.characterization.test.mts",
"site/world-system-views.characterization.test.mts": "site/world/world-system-views.characterization.test.mts",
- "site/zoom-scope.characterization.test.mts": "site/world/zoom-scope.characterization.test.mts",
- "site/object-entry-types.test.mts": "site/directory/object-entry-types.test.mts",
- "site/moon-catalogue.mts": "site/content/moon-catalogue.mts",
- "site/moon-catalogue.test.mts": "site/content/moon-catalogue.test.mts"
+ "site/zoom-scope.characterization.test.mts": "site/world/zoom-scope.characterization.test.mts"
}
diff --git a/docs/site-architecture/tiers.json b/docs/site-architecture/tiers.json
index adb4087aff3..18291227d03 100644
--- a/docs/site-architecture/tiers.json
+++ b/docs/site-architecture/tiers.json
@@ -216,17 +216,17 @@
"site/journeys/astro-component-imports.test.mts",
"site/build/fixtures/authored-object-fixture.mts",
"site/build/prepare/body-additions.test.mts",
- "site/test/body-moons.test.mts",
+ "site/build/prepare/body-moons.test.mts",
"site/journeys/browser-node-imports.test.mts",
"site/server/built-pages.test.mts",
"site/scene/camera-handover.test.mts",
"site/search/catalogue-window.test.mts",
- "site/test/category-frames.test.mts",
+ "site/build/prepare/category-frames.test.mts",
"site/shell/chart-pixel-alignment.test.mts",
"site/build/charts/charts.test.mts",
"site/build/prepare/check-preparation-inputs.test.mts",
"site/journeys/cloudflare-worker.test.mts",
- "site/test/compact-spectrum.test.mts",
+ "site/overview/compact-spectrum.test.mts",
"site/journeys/context-lineage.test.mts",
"site/shell/dataset-picker.test.mts",
"site/server/dataset-response.test.mts",
@@ -261,28 +261,28 @@
"site/search/list-distance.test.mts",
"site/build/content/load-object-content.test-support.mts",
"site/build/prepare/lonlat-slice-table.test.mts",
- "site/test/moon-labels.test.mts",
+ "site/world/moon-labels.test.mts",
"site/navigation/navigation-content.test.mts",
"site/navigation/navigation-fragments.test.mts",
"site/test/navigation-history.test.mts",
"site/navigation/navigation-lifecycle.test.mts",
- "site/test/navigation-ontology.test.mts",
- "site/test/navigation-preparation.test.mts",
+ "site/world/navigation-ontology.test.mts",
+ "site/world/navigation-preparation.test.mts",
"site/navigation/navigation-readiness.test.mts",
- "site/test/navigation-request.test.mts",
- "site/test/navigation-router-context.mts",
+ "site/navigation/navigation-request.test.mts",
+ "site/scene/navigation-router-context.test-support.mts",
"site/test/navigation-scope.test.mts",
"site/navigation/navigation-shell-content.test.mts",
"site/navigation/navigation-styles.test.mts",
- "site/test/navigation-test-values.mts",
+ "site/navigation/navigation-test-values.test-support.mts",
"site/navigation/navigation-timing.test.mts",
- "site/test/nebula-search.test.mts",
+ "site/world/nebula-search.test.mts",
"site/journeys/neutral-catalogue-color.test.mts",
"site/test/object-children.test.mts",
"site/journeys/object-control-binding.test.mts",
"site/test/object-directory.test.mts",
- "site/test/object-navigation.test.mts",
- "site/test/object-package-contract.test.mts",
+ "site/world/object-navigation.test.mts",
+ "site/build/object-package-contract.test.mts",
"site/server/object-page-data.test.mts",
"site/search/object-result.test.mts",
"site/journeys/object-runtime-contract.test.mts",
@@ -296,18 +296,18 @@
"site/build/prepare/prepare-object-json.test.mts",
"site/build/prepare/prepare-spatial-context.test.mts",
"site/build/prepare/prepare-text.test.mts",
- "site/test/prepared-arrival.test.mts",
- "site/test/prepared-body-billboards.test.mts",
+ "site/navigation/prepared-arrival.test.mts",
+ "site/world/prepared-body-billboards.test.mts",
"site/build/content/prepared-dataset-facts.test.mts",
"site/journeys/prepared-dataset-labels.test.mts",
"site/build/content/prepared-dataset-legends.test.mts",
"site/navigation/prepared-descriptor.test.mts",
- "site/test/prepared-icons.test.mts",
+ "site/build/prepare/prepared-icons.test.mts",
"site/build/prepared-motion-css.test.mts",
"site/content/prepared-panel-content.test.mts",
"site/contracts/prepared-presentation-bindings.test.mts",
"site/journeys/prepared-presentation-contract.test.mts",
- "site/test/prepared-world-context.test.ts",
+ "site/world/prepared-world-context.test.ts",
"site/test/prepared-world-navigation.test.mts",
"site/server/preview.test.mts",
"site/journeys/production-diagnostics.test.mts",
@@ -316,17 +316,17 @@
"site/journeys/rendered-page.test.mts",
"site/build/restore-inputs.test.mts",
"site/build/run-script-chain.test.mts",
- "site/test/runtime-package.test.mts",
+ "site/world/runtime-package.test.mts",
"site/browser/runtime-policy.test.mts",
- "site/test/satellite-arrival-framing.test.mts",
+ "site/navigation/satellite-arrival-framing.test.mts",
"site/test/satellite-systems.test.mts",
- "site/test/scene-contract.test.mts",
+ "site/world/scene-contract.test.mts",
"site/scene/scene-datasets.test.mts",
"site/scene/scene-frame.test.mts",
"site/scene/scene-publication.test.mts",
"site/scene/scene-session.test.mts",
- "site/test/search-api.test.mts",
- "site/test/search-response.test.mts",
+ "site/journeys/search-api.test.mts",
+ "site/server/search-response.test.mts",
"site/journeys/seo-discovery.test-support.mts",
"site/journeys/seo-discovery.test.mts",
"site/test/seo.test.mts",
@@ -338,21 +338,21 @@
"site/overview/source-evidence-values.test-support.mts",
"site/browser/source-link.test.mts",
"site/test/startup-billboard.test.mts",
- "site/test/startup-cover.test.mts",
+ "site/browser/startup-cover.test.mts",
"site/directory/startup-requests.test.mts",
"site/test/stellar-extents.test.mts",
"site/journeys/surface-label-loop.test.mts",
"site/minimap/surface-minimap.test.mts",
"site/test/system-framing.test.mts",
- "site/test/system-text.test.mts",
- "site/test/system-view-file.mts",
+ "site/build/prepare/system-text.test.mts",
+ "site/world/system-view-file.test-support.mts",
"site/test/view-readout.test.mts",
"site/navigation/view-url-runtime.test.mts",
"site/content/volume-presentation.test.mts",
"site/browser/web-analytics.test.mts",
"site/journeys/world-billboards.test.mts",
- "site/test/world-stars.test.mts",
- "site/test/world-tables.test.mts",
+ "site/world/world-stars.test.mts",
+ "site/world/world-tables.test.mts",
"site/test/zoom-scope.test.mts",
"site/navigation/view-url-runtime.characterization.test.mts"
],
diff --git a/eslint.config.mts b/eslint.config.mts
index de569c51545..97a0738e1cf 100644
--- a/eslint.config.mts
+++ b/eslint.config.mts
@@ -179,7 +179,7 @@ export default [
// Modules over the line limit that are not split yet.
files: [
'packages/renderer/src/universe/prepared-world-context.ts',
- 'site/test/prepared-world-context.test.ts',
+ 'site/world/prepared-world-context.test.ts',
'packages/renderer/src/universe/world-context/world-context-planner.test.ts',
'packages/renderer/src/sky/prepared-sky-runtime.test.ts',
'packages/telescope-cli/src/archives/interferometry/alma-disc-selfcal.mts',
diff --git a/package.json b/package.json
index 7974263f0c6..9d6208e1bda 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,7 @@
"setup:asset-data": "node packages/bake/cli/setup-assets.mts",
"setup:prepared": "node packages/bake/cli/setup-assets.mts --location=prepared",
"test": "pnpm prepare:environment-images && pnpm prepare:nebulae && pnpm test:packages && pnpm test:site && pnpm test:lab",
- "test:run": "node --import ./packages/core/src/node/register-vite-suffix.mts --import ./site/test/navigation-router-context.mts --experimental-test-module-mocks --test --test-concurrency=4 --test-timeout=180000",
+ "test:run": "node --import ./packages/core/src/node/register-vite-suffix.mts --import ./site/scene/navigation-router-context.test-support.mts --experimental-test-module-mocks --test --test-concurrency=4 --test-timeout=180000",
"test:packages": "pnpm test:run \"packages/**/*.test.{ts,mts}\" \"integration/**/*.test.{ts,mts}\"",
"test:site": "pnpm test:run \"site/**/!(rendered-page).test.{ts,mts}\" \"src/**/*.test.{ts,mts}\" \".github/**/*.test.mts\" \"labs/performance/*.test.mts\"",
"typecheck": "node .github/scripts/ci/checkout/typecheck.mts",
diff --git a/packages/renderer/AGENTS.md b/packages/renderer/AGENTS.md
index 6861af42593..7e6f6b3b911 100644
--- a/packages/renderer/AGENTS.md
+++ b/packages/renderer/AGENTS.md
@@ -87,4 +87,4 @@ surface fly-to calibration belong to `@cssearth/engine`. Renderer extends the en
## Accepted test boundaries
-Node tests beside `src/node/` verify private implementation details; `test/` holds package integration fixtures and helpers. Three explicit `./test/` exports expose only the fixture files imported through package entries. The sole consumer outside renderer is `site/test/runtime-package.test.mts`, which imports `@cssearth/renderer/test/object-runtime-package.mts`; the orbit and camera-orientation fixture exports serve renderer tests.
+Node tests beside `src/node/` verify private implementation details; `test/` holds package integration fixtures and helpers. Three explicit `./test/` exports expose only the fixture files imported through package entries. The sole consumer outside renderer is `site/world/runtime-package.test.mts`, which imports `@cssearth/renderer/test/object-runtime-package.mts`; the orbit and camera-orientation fixture exports serve renderer tests.
diff --git a/packages/renderer/src/node/test-exports.test.mts b/packages/renderer/src/node/test-exports.test.mts
index c322e9f3939..d5ab0226294 100644
--- a/packages/renderer/src/node/test-exports.test.mts
+++ b/packages/renderer/src/node/test-exports.test.mts
@@ -21,7 +21,7 @@ test('renderer fixture exports are exactly the imported test entries', () => {
}
const exported = Object.keys(entries).filter(key => key.startsWith('./test/'));
assert.deepEqual(exported.sort(), [...imports].sort());
- assert.deepEqual([...external], ['site/test/runtime-package.test.mts']);
+ assert.deepEqual([...external], ['site/world/runtime-package.test.mts']);
for (const entry of exported) {
assert.equal(requireString(entries[entry]), entry);
assert.ok(import.meta.resolve(`@cssearth/renderer/${entry.slice(2)}`).endsWith(entry.slice(1)));
diff --git a/site/application-world-context.mts b/site/application-world-context.mts
index 189c9b23808..a08bc291396 100644
--- a/site/application-world-context.mts
+++ b/site/application-world-context.mts
@@ -15,7 +15,7 @@ import { mountCatalogueMoonLabels } from './catalogue-moon-labels.mts';
import { loadApplicationUniverse } from './application-world-resources.mts';
import { ancestorIds, knownAncestors } from './object-directory.mts';
import { CONTEXT_OBJECT_DESCRIPTORS } from './prepared-context-objects.mts';
-import { surroundingHosts } from './surrounded-body.mts';
+import { surroundingHosts } from './world/surrounded-body.mts';
/** The world's prepared data and planner worker, which `startup-boot.mts` starts while the first body still loads. */
export { loadApplicationUniverse };
diff --git a/site/test/startup-cover.test.mts b/site/browser/startup-cover.test.mts
similarity index 100%
rename from site/test/startup-cover.test.mts
rename to site/browser/startup-cover.test.mts
diff --git a/site/test/object-package-contract.test.mts b/site/build/object-package-contract.test.mts
similarity index 96%
rename from site/test/object-package-contract.test.mts
rename to site/build/object-package-contract.test.mts
index 685af199669..5a38f7016dd 100644
--- a/site/test/object-package-contract.test.mts
+++ b/site/build/object-package-contract.test.mts
@@ -6,16 +6,16 @@ import { mkdtemp, mkdir, writeFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { dirname, resolve } from "node:path";
-import { required } from './navigation-test-values.mts';
+import { required } from '../navigation/navigation-test-values.test-support.mts';
import { SCENE_OBJECTS } from "../objects.mts";
-import { authoredObjectFixture } from "../build/fixtures/authored-object-fixture.mts";
+import { authoredObjectFixture } from "./fixtures/authored-object-fixture.mts";
import { objectInformationSource, validateObjectEditorial } from "@cssearth/bake/sources";
import {
objectPackagePaths,
validateObjectPackageFiles,
validateObjectData,
validateInventory,
-} from "../build/object-package-contract.mts";
+} from "./object-package-contract.mts";
const implemented = SCENE_OBJECTS;
diff --git a/site/test/body-moons.test.mts b/site/build/prepare/body-moons.test.mts
similarity index 89%
rename from site/test/body-moons.test.mts
rename to site/build/prepare/body-moons.test.mts
index 63b80a673b6..88d2a33d7f0 100644
--- a/site/test/body-moons.test.mts
+++ b/site/build/prepare/body-moons.test.mts
@@ -1,8 +1,8 @@
import assert from 'node:assert/strict';
import { sourceTest } from '@cssearth/objects/node/source-test';
const test = sourceTest();
-import catalogues from '../source/moon-catalogues.json' with { type: 'json' };
-import { parseMoonCatalogue, prepareBodyMoons } from '../prepare-body-moons.mts';
+import catalogues from '../../source/moon-catalogues.json' with { type: 'json' };
+import { parseMoonCatalogue, prepareBodyMoons } from '../../prepare-body-moons.mts';
const catalogue = catalogues.systems.find(system => system.id === 'saturn')!;
test('Saturn lists every source moon and only links registered scene objects', () => {
diff --git a/site/test/category-frames.test.mts b/site/build/prepare/category-frames.test.mts
similarity index 95%
rename from site/test/category-frames.test.mts
rename to site/build/prepare/category-frames.test.mts
index 2eed51bb114..ff8460fb217 100644
--- a/site/test/category-frames.test.mts
+++ b/site/build/prepare/category-frames.test.mts
@@ -2,9 +2,9 @@ import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { sourceTest } from '@cssearth/objects/node/source-test';
-import { notableBodies, prepareCategoryFrame, CATEGORY_FRAMED_SHARE } from '../build/prepare/prepare-world-presentation.mts';
-import { PREPARED_WORLD_PRESENTATION } from '../prepared-world-presentation.mts';
-import { CATEGORY_FRAMES, categoryZoomTarget } from '../system-framing.mts';
+import { notableBodies, prepareCategoryFrame, CATEGORY_FRAMED_SHARE } from './prepare-world-presentation.mts';
+import { PREPARED_WORLD_PRESENTATION } from '../../prepared-world-presentation.mts';
+import { CATEGORY_FRAMES, categoryZoomTarget } from '../../system-framing.mts';
const test = sourceTest();
test('a category frames the nearest members around their own centre, leaving the far outliers out', () => {
diff --git a/site/test/prepared-icons.test.mts b/site/build/prepare/prepared-icons.test.mts
similarity index 85%
rename from site/test/prepared-icons.test.mts
rename to site/build/prepare/prepared-icons.test.mts
index e7329d411a5..2b25388a6f9 100644
--- a/site/test/prepared-icons.test.mts
+++ b/site/build/prepare/prepared-icons.test.mts
@@ -4,11 +4,11 @@ import { tmpdir } from "node:os";
import { resolve } from "node:path";
import { sourceTest } from '@cssearth/objects/node/source-test';
const test = sourceTest();
-import { SourceEvidence } from "../overview/source-evidence-values.test-support.mts";
+import { SourceEvidence } from "../../overview/source-evidence-values.test-support.mts";
-import { prepareShellIcons } from "../build/prepare/prepare-shell-icons.mts";
-import { PREPARED_SHELL_ICONS } from "../prepared-shell-icons.mjs";
-import { SHELL_ICON_SOURCES } from "../source/icons/manifest.mts";
+import { prepareShellIcons } from "./prepare-shell-icons.mts";
+import { PREPARED_SHELL_ICONS } from "../../prepared-shell-icons.mjs";
+import { SHELL_ICON_SOURCES } from "../../source/icons/manifest.mts";
const projectRoot = resolve(import.meta.dirname, "../..");
diff --git a/site/test/system-text.test.mts b/site/build/prepare/system-text.test.mts
similarity index 81%
rename from site/test/system-text.test.mts
rename to site/build/prepare/system-text.test.mts
index 91c7ebd877a..7e9d38762af 100644
--- a/site/test/system-text.test.mts
+++ b/site/build/prepare/system-text.test.mts
@@ -1,16 +1,16 @@
import assert from 'node:assert/strict';
import { sourceTest } from '@cssearth/objects/node/source-test';
import { readSourceCatalog } from '@cssearth/bake/sources';
-import input from '../../src/navigation/system-text.json' with { type: 'json' };
-import { allSatelliteSystems } from '../satellite-systems.mts';
-import { requireObject } from '../objects.mts';
-import { systemObjectId } from '../model/system-address.mts';
-import { prepareSystemIntroductions } from '../build/prepare/system-text.mts';
-import { showsDefaultContextOrbit } from '../build/prepare/prepare-world-presentation.mts';
+import input from '../../../src/navigation/system-text.json' with { type: 'json' };
+import { allSatelliteSystems } from '../../satellite-systems.mts';
+import { requireObject } from '../../objects.mts';
+import { systemObjectId } from '../../model/system-address.mts';
+import { prepareSystemIntroductions } from './system-text.mts';
+import { showsDefaultContextOrbit } from './prepare-world-presentation.mts';
const test = sourceTest();
test('every satellite system has a cited introduction, which is its system object\'s description', async () => {
- const catalogue = await readSourceCatalog(new URL('../../', import.meta.url).pathname);
+ const catalogue = await readSourceCatalog(new URL('../../../', import.meta.url).pathname);
const hosts = allSatelliteSystems().map(system => system.hostId);
const prepared = prepareSystemIntroductions(input, hosts, new Set(catalogue.records.map(record => record.id)));
assert.deepEqual(prepared, Object.fromEntries(hosts.map(id => [id, requireObject(systemObjectId(id)).description])));
diff --git a/site/moon-catalogue.mts b/site/content/moon-catalogue.mts
similarity index 94%
rename from site/moon-catalogue.mts
rename to site/content/moon-catalogue.mts
index 907f53f12c2..eff6e9355c4 100644
--- a/site/moon-catalogue.mts
+++ b/site/content/moon-catalogue.mts
@@ -1,4 +1,4 @@
-import moonCatalogues from './source/moon-catalogues.json' with { type: 'json' };
+import moonCatalogues from '../source/moon-catalogues.json' with { type: 'json' };
import { sourceArray, sourceId, sourceObject, sourceText, sourceUnique } from '@cssearth/objects/sources';
/** Read names from the source catalogue without creating scene objects or invented positions. */
diff --git a/site/moon-catalogue.test.mts b/site/content/moon-catalogue.test.mts
similarity index 89%
rename from site/moon-catalogue.test.mts
rename to site/content/moon-catalogue.test.mts
index f6f41493ee6..d29c7b8706d 100644
--- a/site/moon-catalogue.test.mts
+++ b/site/content/moon-catalogue.test.mts
@@ -1,7 +1,7 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import test from 'node:test';
-import moonCatalogues from './source/moon-catalogues.json' with { type: 'json' };
+import moonCatalogues from '../source/moon-catalogues.json' with { type: 'json' };
import { sourceArray, sourceId, sourceObject, sourceText, sourceUnique } from '@cssearth/objects/sources';
import { catalogueMoons, parseMoonCatalogue, readMoonCatalogue } from './moon-catalogue.mts';
import ts from 'typescript';
@@ -54,11 +54,11 @@ function modulesNamedBy(file: URL): string[] {
}
test('production children read the shared reader and never name preparation; preparation has one reader', () => {
- const children = modulesNamedBy(new URL('./object-children.mts', import.meta.url));
+ const children = modulesNamedBy(new URL('../object-children.mts', import.meta.url));
const reader = new URL('./moon-catalogue.mts', import.meta.url).pathname;
assert.ok(children.includes(reader), 'Children use the shared reader');
- assert.ok(!children.includes(new URL('./prepare-body-moons.mts', import.meta.url).pathname), 'Children never import preparation');
- const preparation = modulesNamedBy(new URL('./prepare-body-moons.mts', import.meta.url));
+ assert.ok(!children.includes(new URL('../prepare-body-moons.mts', import.meta.url).pathname), 'Children never import preparation');
+ const preparation = modulesNamedBy(new URL('../prepare-body-moons.mts', import.meta.url));
assert.ok(preparation.includes(reader), 'Preparation reads the shared catalogue');
assert.ok(!preparation.some(module => module.endsWith('/moon-catalogues.json') || module === '@cssearth/objects/sources'), 'Preparation must not re-parse a separate catalogue');
});
diff --git a/site/destination-browser.characterization.test.mts b/site/destination-browser.characterization.test.mts
index 667b275fbc6..a72039f3ef0 100644
--- a/site/destination-browser.characterization.test.mts
+++ b/site/destination-browser.characterization.test.mts
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict';
import test from 'node:test';
import { parseHTML } from 'linkedom';
import { createDestinationBrowser } from './destination-browser.mts';
-import { required } from './test/navigation-test-values.mts';
+import { required } from './navigation/navigation-test-values.test-support.mts';
test('destination panel publishes city fields, opens only once per selection and forwards reset', () => {
const { document } = parseHTML('