Skip to content
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
2 changes: 1 addition & 1 deletion packages/bake/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ its validators accept); the renderer never imports the bake.
writes and tests read back, with its prepared resource catalogue, validated against the prepared-presentation contract
and the renderer's object controls, and the audits that read a prepared presentation and its authored runtime sources back
against the descriptor (`check-prepared-presentation.ts`; the prepared format constant comes
from the renderer's `prepared-data/object-format.ts`). The audit reads the registry on first use, not at import. It imports
from `@cssearth/objects`). The audit reads the registry on first use, not at import. It imports
`presentation`, `runtime-source` and `sources`. `packages/bake/cli/check-prepared-presentation.mts` is the audit's command,
run for each object by the `audit` step of `prepare-object`. `prepared-object-pin.ts` pins a prepared object to its
transport (the descriptor's `prepared` pin and page reference, and the inventory; the transports themselves are built from
Expand Down
2 changes: 1 addition & 1 deletion packages/bake/src/contract/check-prepared-presentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { ObjectEntry } from '@cssearth/objects';
import { requirePreparedPresentation, PREPARED_OBJECT_RUNTIME_SCHEMA } from "../presentation/index.ts";
import { requireObjectRuntimeDefinition } from "./object-runtime-contract.ts";
import { requireAuthoredWorldFrame } from '../sources/index.ts';
import { PREPARED_CSS_OBJECT_FORMAT } from '@cssearth/renderer/prepared-data/object-format.ts';
import { PREPARED_CSS_OBJECT_FORMAT } from '@cssearth/objects';
import { requireObjectControls } from '@cssearth/renderer/runtime/shell-contract.ts';
import { nodeName, staticObjectProperties } from '../runtime-source/index.ts';
import type { RuntimeSourceReader } from '../runtime-source/index.ts';
Expand Down
2 changes: 1 addition & 1 deletion packages/bake/src/contract/prepared-object-pin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { dirname, resolve } from 'node:path';
import { requireRecord } from '@cssearth/core';
import { parseObjectDescriptor } from '@cssearth/objects';
import { inventoryPreparedAssets, readInventory } from '@cssearth/objects/node';
import { PREPARED_CSS_OBJECT_FORMAT } from '@cssearth/renderer/prepared-data/object-format.ts';
import { PREPARED_CSS_OBJECT_FORMAT } from '@cssearth/objects';
import { preparePageMetadata, writePreparedText } from '../delivery/index.ts';
import { requireObjectRuntimeDefinition } from './object-runtime-contract.ts';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {readAuthoredSources} from '../../sources/index.ts';
import {parse} from '@cssearth/core/schema';
import {PREPARED_CSS_OBJECT_FORMAT} from '@cssearth/renderer/prepared-data/object-format.ts';
import {PREPARED_CSS_OBJECT_FORMAT} from '@cssearth/objects';
import { layeredRecipe } from './layered-recipe.ts';
import { spectralRecipe } from './spectral-recipe.ts';
import { radialMotionRecipe } from './radial-motion-recipe.ts';
Expand Down
3 changes: 3 additions & 0 deletions packages/objects/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ layer-plan/report readers and render-element budgets; exported through the main
volume and sampled recipes, emission-fit settings, physical slice formats and validation, compiler controls and star
inputs, joint parameters, authored shape settings, observation photo data and prepared catalogue stars. Writers and
readers import these from `@cssearth/objects`; sampling, fitting, cancellation and file I/O remain outside this area.
`src/prepared-data/` owns the prepared CSS object format identifier and compact world-summary/system table decoders,
exported through the browser-safe main entry. Full world-context validation still resides in renderer pending extraction of shared frame/presentation contracts
from camera/projection modules; do not import renderer implementation here.
An object type describes supported behavior and data, not an individual planet.
Do not ship per-object configuration, generated payload modules, shell content, or renderer code here.
Keep one shared object contract; application discovery remains in the existing registry.
Expand Down
5 changes: 5 additions & 0 deletions packages/objects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,8 @@ per-planet code or data folders. Concrete CSS/DOM rendering belongs to the
application renderer. Earth is a future consumer, outside this migration's scope.

Prepared volume scene contracts and their pure validators/helpers live in `src/volume/`, exported by `@cssearth/objects`. This includes volume and sampled recipes, emission-fit settings, slice data and layer validation, compiler controls and star inputs, joint parameters, authored shape settings, observation photo data and prepared catalogue stars. Writers and readers import the same contracts here. Baking, fitting, sampling, cancellation and I/O remain in `@cssearth/bake`.

The browser-safe main entry exports `PREPARED_CSS_OBJECT_FORMAT`, `expandWorldContextSummary()` and
`expandWorldSystem()` from `src/prepared-data/`. The decoders expand compact body columns, shared tables,
billboards and orbit centres before validation. Full world-context validation still lives in the renderer,
where its shared geometry parser depends on camera/projection implementation.
2 changes: 2 additions & 0 deletions packages/objects/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ export * from './volume/sampled-emission-fit.js';
export * from './volume/sampled-recipe.js';
export * from './volume/volume-recipe.js';
export * from './volume/volume-slices.js';
export { PREPARED_CSS_OBJECT_FORMAT } from './prepared-data/object-format.js';
export { expandWorldContextSummary, expandWorldSystem } from './prepared-data/world-context-summary.js';
48 changes: 48 additions & 0 deletions packages/objects/src/prepared-data/world-context-summary.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { expandWorldContextSummary, expandWorldSystem } from './world-context-summary.js';
import { PREPARED_CSS_OBJECT_FORMAT } from './object-format.js';

const summary = () => ({
schema: 'cssearth-world-context-summary@2',
systemNames: ['Solar System'], discoveries: [{ method: 'imaging' }],
billboard: { size: 512, focalPixels: 256, distanceRadii: 8 },
focus: { id: 'sun', positionM: [0, 0, 0], radiusM: 10 },
bodies: { id: ['earth'], radiusM: [2], positionM: [[20, 0, 0]], system: [0], discovery: [0],
billboard: [{}], orbit: [{ centerBodyId: 'sun', bounds: { centerM: [0, 0, 0], radiusM: 20 }, lod: true }], optional: [null] },
deferred: { id: ['moon'], host: ['earth'], system: [0], discovery: [0] },
});

test('prepared format and compact world tables preserve the expanded transport shape', () => {
assert.equal(PREPARED_CSS_OBJECT_FORMAT, 'cssearth-css-object@5');
assert.deepEqual(expandWorldContextSummary(summary()), {
schema: 'cssearth-world-context-summary@2', focus: { id: 'sun', positionM: [0, 0, 0], radiusM: 10 },
bodies: [{ id: 'earth', radiusM: 2, positionM: [20, 0, 0], systemName: 'Solar System', discovery: { method: 'imaging' },
billboard: { url: '/scenes/earth/earth-billboard.webp', size: 512, focalPixels: 256, distanceM: 16 },
orbit: { centerBodyId: 'sun', centerPositionM: [0, 0, 0], bounds: { centerM: [0, 0, 0], radiusM: 20 },
lod: { bounds: { centerM: [0, 0, 0], radiusM: 20 } } } }],
deferred: [{ id: 'moon', host: 'earth', systemName: 'Solar System', discovery: { method: 'imaging' } }],
});
const expanded = { schema: 'cssearth-world-context-summary@2', bodies: [] };
assert.equal(expandWorldContextSummary(expanded), expanded);
});

test('compact world tables reject unequal columns, missing entries and unknown orbit centres', () => {
const unequal = summary(); unequal.bodies.id.push('mars');
assert.throws(() => expandWorldContextSummary(unequal), /has 1 entries, not 2/);
const missing = summary(); missing.bodies.system[0] = 1;
assert.throws(() => expandWorldContextSummary(missing), /not an index into its 1-entry table/);
const unknown = summary(); unknown.bodies.orbit[0]!.centerBodyId = 'missing';
assert.throws(() => expandWorldContextSummary(unknown), /parent missing is not placed/);
});

test('deferred systems resolve shared orbit centres without overriding explicit billboard fields', () => {
const input = { schema: 'cssearth-world-system@1', id: 'earth', systemNames: [], discoveries: [], billboard: {},
bodies: { id: ['moon'], radiusM: [1], billboard: [{ url: '/moon.webp', size: 32, focalPixels: 16, distanceM: 12 }],
orbit: [{ centerBodyId: 'earth' }] } };
assert.deepEqual(expandWorldSystem(input, id => id === 'earth' ? [20, 0, 0] : undefined), {
schema: 'cssearth-world-system@1', id: 'earth', bodies: [{ id: 'moon', radiusM: 1,
billboard: { url: '/moon.webp', size: 32, focalPixels: 16, distanceM: 12 },
orbit: { centerBodyId: 'earth', centerPositionM: [20, 0, 0] } }],
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { array, positive, record, text, unique } from '../validation/guards.js';
import { checks, failure } from '@cssearth/core';

const { array, positive, record, text, unique } = checks(failure('Prepared presentation: '));

/** `world-context-summary.json` and each `world-systems/<star id>.json` write what many bodies repeat once
* (`summarizeWorldContext` in @cssearth/bake). These put each body back in the shape `parsePreparedWorldContextSummary`
Expand Down
3 changes: 2 additions & 1 deletion packages/renderer/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ Own the CSS renderer runtime: loading, decoding and validating prepared objects,
navigation, retained CSS rendering of bodies, skies, stars, volumes, image layers and labels, and the universe context
around the focused object. The site and the preparation tools reach it through `@cssearth/renderer` and its subpaths.
The compilers that write the renderer's prepared formats are preparation code; they live in `@cssearth/bake` and import
this package.
this package. Shared format identifiers and compact world-summary/system table decoders live in
`@cssearth/objects`; camera/projection-dependent world-context validation remains here.

## The runtime contract

Expand Down
4 changes: 3 additions & 1 deletion packages/renderer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
The CSS renderer runtime. It loads, decodes and validates prepared objects, keeps the one shared world camera and its
navigation, and renders bodies, skies, star fields, volumes, image layers and labels as retained PolyCSS and CSS, with
the universe context around the focused object. The site mounts objects through it; the preparation tools import its
formats and validators so that what they write is what the browser reads.
validators so that what they write is what the browser reads. The prepared CSS format identifier and compact
world-summary/system table decoders are shared through `@cssearth/objects`. The world-context parser remains here
because its full/summary validation shares geometry and camera/projection dependencies.

It was `src/renderers/css` until 2026-09-26. The compilers that write its prepared formats stayed there
(`src/renderers/css/preparation`) until they moved into `@cssearth/bake`; the object page stylesheets
Expand Down
2 changes: 1 addition & 1 deletion packages/renderer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type { PreparedAssets } from './rendering/prepared-residency.js';
export { resolvePreparedAssetUrl, rewritePreparedStyleUrls, parsePreparedAssetOrigin, preparedAssetGroup, preparedAssetGroupFile, createPreparedAssetResolver } from './rendering/prepared-asset-origin.js';
export type { PreparedAssetOrigin } from './rendering/prepared-asset-origin.js';
export { CANONICAL_PREPARED_IMAGE_DENSITY } from './rendering/prepared-object-assets.js';
export { loadPreparedCssObject, loadPreparedDataset, PREPARED_CSS_OBJECT_FORMAT } from './loader.js';
export { loadPreparedCssObject, loadPreparedDataset } from './loader.js';
export { adoptPreparedDatasetTables, splitPreparedDatasetTables, deferredDatasetIds, preparedDatasetReference } from './prepared-data/dataset-tables.js';
export type { PreparedDatasetTables } from './prepared-data/dataset-tables.js';
export type { PreparedCssTransport } from './loader.js';
Expand Down
1 change: 0 additions & 1 deletion packages/renderer/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { decodePreparedCssObject, requirePreparedCssDescriptor } from './prepare
import { decodePreparedObjectInWorker } from './prepared-object-worker-client.js';
import { adoptPreparedDatasetTables, preparedDatasetReference } from './prepared-data/dataset-tables.js';

export { PREPARED_CSS_OBJECT_FORMAT } from './prepared-object-decoder.js';
export interface PreparedCssTransport {
/** Return the exact bytes addressed by the prepared reference. The decoder
* owns this buffer and may transfer it to a worker. */
Expand Down
2 changes: 1 addition & 1 deletion packages/renderer/src/prepared-data/world-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { PreparedWorldCameraFrame } from '../navigation/world-camera.js';
import { cssViewFromOrientation, validateWorldRotation } from '../navigation/world-camera-math.js';
import type { LevelOfDetailPlan, OrbitLineFade } from '../navigation/types.js';
import type { PreparedOrbitStrokes } from '../solar-system/prepared-orbit-strokes.js';
import { expandWorldContextSummary, expandWorldSystem } from './world-context-summary.js';
import { expandWorldContextSummary, expandWorldSystem } from '@cssearth/objects';
import { parseClassificationViews, parseSystemView } from './world-system-view.js';
import type { PreparedSystemViewCandidate } from './world-system-view.js';
export { parsePreparedSystemView, type PreparedSystemViewCandidate } from './world-system-view.js';
Expand Down
4 changes: 1 addition & 3 deletions packages/renderer/src/prepared-object-decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import { parsePreparedObjectRuntime } from './validation/index.js';
import type { ObjectRuntimeDefinition } from './runtime/object-runtime-types.js';
import { record } from './validation/guards.js';
import { parsePreparedAssetOrigin } from './rendering/prepared-asset-origin.js';
import { PREPARED_CSS_OBJECT_FORMAT } from './prepared-data/object-format.js';

export { PREPARED_CSS_OBJECT_FORMAT };
import { PREPARED_CSS_OBJECT_FORMAT } from '@cssearth/objects';

export function requirePreparedCssDescriptor(input: unknown) {
const descriptor = parseObjectDescriptor(input);
Expand Down
2 changes: 1 addition & 1 deletion site/asset-origin.mts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export async function rewriteSceneCss(css: string, root = process.cwd()): Promis
}

/** A world file (`world-context-summary.json` or `world-systems/<star>.json`) with every billboard's published address.
* The file leaves a body's own `/scenes/<id>/<id>-billboard.webp` implicit (world-context-summary.ts), and production serves
* The file leaves a body's own `/scenes/<id>/<id>-billboard.webp` implicit (`packages/objects/src/prepared-data/world-context-summary.ts`), and production serves
* no `/scenes`: the build writes the bucket's address for each. No-op when unset. */
export async function resolveWorldBillboards(text: string, root = process.cwd()): Promise<string> {
if (!assetOrigin()) return text;
Expand Down
Loading