The sky gets the things above the aeroplanes
Satellites, end to end: CelesTrak element sets behind the same TTL cache
the weather and the flights use, served as TLEs rather than as positions,
and propagated in the browser with SGP4.
Sending elements is the same trick `flights/plan.ts` plays and it has a
better excuse here — a TLE *is* the closed form, valid for days either
side of its epoch, so one cacheable fetch every six hours replaces a poll
and every viewer agrees about where everything is.
Two things are worth knowing about the shape of it:
- There is no region parameter. An aeroplane at 10,000 m is local and
a satellite at 550 km is above the horizon for a circle two thousand
kilometres across, so one catalogue serves both boards and the client
decides what is above its own horizon. Only the observer is per-city,
which is why `main.ts` shares the elements and rebuilds the catalogue.
- The layer draws on a dome, because it cannot draw anywhere else.
`world.metres(550_000)` is 21,000 scene units against a far plane at
3,000. Azimuth and elevation are real; the radius carries nothing.
Off by default: a clone that started pulling CelesTrak on `npm run dev`
would have volunteered somebody else's bandwidth for its onboarding.
Godmode gets the two dials that point at the sky rather than at the
light — fabricated traffic, which composes with a live ADS-B feed instead
of replacing it, and a switch for the satellite layer with a count beside
it. Both are god-only lies about the inputs, in the manner of the weather
override.
`satellite.js` is the second runtime dependency this package has taken.
Its entry point star-exports an Emscripten build that cannot be shaken
out, so `noWasmPropagator` in the Vite config cuts it: 308 kB of WASM
loader for a bulk propagator nothing calls, against 26 kB for the SGP4
that does the work.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+55
-1
@@ -97,11 +97,65 @@ function twoDoors(): Plugin {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut `satellite.js`'s WASM runtime out of the bundle.
|
||||
*
|
||||
* `satellite.js`'s entry point ends with `export * from './wasm/index.js'`, and
|
||||
* that subtree is an Emscripten build: a megabyte of generated glue that reaches
|
||||
* for `node:module` and `node:worker_threads`, wraps itself in a top-level
|
||||
* `await`, and cannot be tree-shaken away because a star re-export of a module
|
||||
* with side effects is not something a bundler may drop on its own.
|
||||
*
|
||||
* Measured, before this existed: **308 kB** of minified WASM loader shipped to
|
||||
* every visitor, in a chunk nothing ever called. `engine/satellites.ts` uses the
|
||||
* pure-JS `propagate` and says in its own header why it does not want the
|
||||
* `BulkPropagator` — a binary loaded at runtime plus a fallback path for when
|
||||
* that fails, to buy back two milliseconds a frame that are already budgeted.
|
||||
* Paying 308 kB to *not* use it was the worst of both.
|
||||
*
|
||||
* The stub is empty because nothing imports a name from it. If a future version
|
||||
* of this repo does want the bulk propagator, the fix is to delete this plugin
|
||||
* and pay the kilobytes deliberately — not to widen the stub.
|
||||
*
|
||||
* Matching is on the **importer** as well as the specifier, so this cannot
|
||||
* silently swallow some other package's `./wasm/index.js`.
|
||||
*/
|
||||
function noWasmPropagator(): Plugin {
|
||||
const STUB = "\0lumbridge:satellite-wasm-stub";
|
||||
return {
|
||||
name: "lumbridge:no-wasm-propagator",
|
||||
enforce: "pre",
|
||||
resolveId(source, importer) {
|
||||
if (source !== "./wasm/index.js") return null;
|
||||
if (importer === undefined || !importer.includes("satellite.js")) return null;
|
||||
return STUB;
|
||||
},
|
||||
load(id) {
|
||||
return id === STUB ? "export {};" : null;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
// Mounted under tera.lumbridgecorp.com in production; the trailing
|
||||
// slash matters, since every asset URL is resolved against it.
|
||||
base: process.env.TERA_BASE ?? "/",
|
||||
plugins: [twoDoors()],
|
||||
plugins: [noWasmPropagator(), twoDoors()],
|
||||
/**
|
||||
* The heightfield worker is constructed as `{ type: "module" }` in
|
||||
* `world.ts`, and this is the build setting that agrees with it.
|
||||
*
|
||||
* Vite's default worker format is `iife`, which was survivable while nothing
|
||||
* in the graph needed anything an IIFE cannot express — and stopped being
|
||||
* survivable the moment it did. `satellite.js` reaches a WASM runtime with a
|
||||
* top-level `await` in it, and rollup's answer to a top-level await in an
|
||||
* `iife` chunk is to fail the whole build, with an error naming a file no
|
||||
* worker imports.
|
||||
*
|
||||
* So this is agreement rather than a workaround: the module the browser is
|
||||
* told to load as an ES module is now built as one.
|
||||
*/
|
||||
worker: { format: "es" },
|
||||
build: {
|
||||
outDir: "dist",
|
||||
target: "es2022",
|
||||
|
||||
Reference in New Issue
Block a user