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: 2 additions & 0 deletions packages/engine/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Do not import the application, legacy runtime, or object-specific configuration.
- Every source file, test, tool, and generated source is limited to 600 physical lines, including blanks/comments.
- `pnpm lint:packages` enforces the limit. Split code by responsibility; keep bulk prepared data outside source code.
- Maintain README.md and CLAUDE.md as a symlink to this guide. Test behavior and package boundaries.
- The site's client build compiles the main entry from its sources and marks every module free of side effects
([package-sources.mts](../../site/build/package-sources.mts)), so modules declare and export only.

Numeric camera orientation math, heliocentric geometry and solar direction conversions live in `src/navigation/` and `src/solar-system/`, exported by the main entry. They depend on core numerics; no renderer, DOM or resource-loading implementation is imported. Flat solar matrices use the public `FlatMatrix3` name; navigation `Matrix3` remains nested.

Expand Down
9 changes: 6 additions & 3 deletions site/build/package-sources.mts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@ import { fileURLToPath } from 'node:url';
import type { Plugin } from 'vite';
import rendererConfig from '../../packages/renderer/tsup.config.ts';
import objectsConfig from '../../packages/objects/tsup.config.ts';
import engineConfig from '../../packages/engine/tsup.config.ts';

// tsup's shared chunks reach the client bundler as single modules, so one startup import pulled every
// renderer module sharing that chunk (the universe, volume and star runtimes) into the first load, and every
// object contract the objects package's one bundle holds into the chunk of its first importer.
// object contract the objects package's one bundle holds into the chunk of its first importer. The engine's one bundle
// did the same: the startup cover's single `smoothstep` put the whole engine (29.6 KB of 50.8 KB) in every page's first load.
// The client build compiles the same entries from their TypeScript sources and splits per module.
// Renderer and objects modules only declare and export, so an unused one is dropped rather than kept for its
// Renderer, objects and engine modules only declare and export, so an unused one is dropped rather than kept for its
// load-time effects; worker entries keep theirs. Server rendering and Node tools keep the built packages.
const packages: readonly { name: string; directory: string; config: unknown }[] = [
{ name: '@cssearth/renderer', directory: 'renderer', config: rendererConfig },
{ name: '@cssearth/objects', directory: 'objects', config: objectsConfig }];
{ name: '@cssearth/objects', directory: 'objects', config: objectsConfig },
{ name: '@cssearth/engine', directory: 'engine', config: engineConfig }];
const built = packages.map(({ name, directory, config }) => {
const root = fileURLToPath(new URL(`../../packages/${directory}/`, import.meta.url));
return { name, sources: `${root}src/`, entries: new Map<string, string>(entryPairs(config, root).map(([output, source]) => [`${root}dist/${output}.js`, source])) };
Expand Down
5 changes: 3 additions & 2 deletions site/scene/object-adapter.mts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { importPackagedObjectRuntime } from './scene-imports.mts';
import { parseObjectDescriptor, type ObjectDescriptor } from '@cssearth/objects';
import type { ObjectEntry } from '../directory/objects.mts';
// The router that holds this adapter imports the directory statically, so a dynamic import here only added a facade chunk.
import { loadObject } from '../directory/object-directory.mts';

export const objectAdapter = Object.freeze({
/** A page's own prepared descriptor mounts without the registry, so the first body loads before it. */
Expand All @@ -12,8 +14,7 @@ export const objectAdapter = Object.freeze({
const { loadPackagedObject } = await importPackagedObjectRuntime();
mount = await loadPackagedObject(preparedDescriptor, signal);
} else {
const directory = objects ? null : await import('../directory/object-directory.mts');
const loaded = directory ? await directory.loadObject(objectId) : objects!.find(({ id }) => id === objectId);
const loaded = objects ? objects.find(({ id }) => id === objectId) : await loadObject(objectId);
const objectRecord = loaded ?? null;
if (!objectRecord) throw new Error(`Unknown cssEarth object: ${objectId ?? "unknown"}.`);
mount = await objectRecord.loadScene(signal);
Expand Down
Loading