@inventure71/paddockjs 4.0.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/INSTALL_AND_UPDATE.md +14 -1
- package/README.md +33 -1
- package/docs/architecture.md +3 -1
- package/docs/component_inventory.md +5 -4
- package/docs/composable-layouts.md +2 -0
- package/docs/data_contract.md +5 -1
- package/docs/getting-started.md +33 -0
- package/docs/index.md +4 -2
- package/docs/loading.md +141 -0
- package/docs/system_specs.md +15 -2
- package/docs/testing-reliability-guide.md +62 -0
- package/package.json +16 -9
- package/src/data/index.d.ts +64 -1
- package/src/environment/index.d.ts +75 -12
- package/src/index.d.ts +72 -6
- package/src/placeholder/index.d.ts +11 -0
- package/src/placeholder/index.js +61 -0
- package/src/placeholder.css +72 -0
- package/src/simulation/collisionGeometry.js +7 -9
- package/src/simulation/driver/driverController.js +2 -2
- package/src/simulation/driver/edgeRecovery.js +2 -2
- package/src/simulation/driver/racingControls.js +35 -25
- package/src/simulation/driver/racingLinePlan.js +6 -5
- package/src/simulation/driver/rejoinControls.js +3 -3
- package/src/simulation/driver/trafficScan.js +48 -22
- package/src/simulation/participants/participantInteractions.js +24 -15
- package/src/simulation/race/raceStep.js +19 -10
- package/src/simulation/race/safetyCar.js +2 -1
- package/src/simulation/rules/pitLaneSpeedingSteward.js +1 -1
- package/src/simulation/rules/rulesReview.js +19 -9
- package/src/simulation/rules/trackLimitsSteward.js +2 -2
- package/src/simulation/timing/sectorPerformance.js +11 -3
- package/src/simulation/track/spatialQueries.js +80 -11
- package/src/simulation/track/trackModel.js +10 -1
- package/src/simulation/vehicle/contactResolution.js +4 -4
- package/src/simulation/vehicle/vehicleGeometry.js +87 -49
- package/src/simulation/vehicle/vehiclePhysics.js +7 -2
- package/src/simulation/vehicle/vehicleSnapshots.js +5 -2
- package/src/simulation/vehicle/vehicleState.js +3 -2
- package/src/ui/raceCanvasTemplate.js +3 -2
- package/src/ui/raceControlsTemplate.js +1 -0
- package/src/ui/telemetryDrawerTemplate.js +1 -0
- package/src/ui/telemetryTemplates.js +1 -0
- package/examples/train-basic-policy.mjs +0 -276
- package/examples/trainingData.mjs +0 -133
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Tighten the package boundary around supported simulator, environment, display, data, and Python policy-server example surfaces. Local JavaScript training experiments now live outside the published package surface, and release-facing docs no longer advertise the removed local starter trainer as packaged guidance.
|
|
8
|
+
- Keep browser expert resets aligned with the resolved `physicsMode` and harden unsupported physics-mode handling so documented hosts continue to use only `arcade` or `advanced`.
|
|
9
|
+
- Add stricter CLI validation for release and diagnostic scripts. Browser smoke, consumer smoke, bundle-boundary checks, runtime benchmarks, track-query benchmarks, and hotspot profiling now provide clean help output and reject unknown or conflicting arguments before running expensive work.
|
|
10
|
+
- Clean up showcase/package-boundary examples so rendered snippets import only public package symbols and leave preview-local policy adapters as host-owned code.
|
|
11
|
+
|
|
12
|
+
### Performance And Runtime
|
|
13
|
+
|
|
14
|
+
- Reduce hot-loop allocations in built-in driver control by reusing racing-line profiles, traffic scan entries, lookahead sample objects, and target-point scratch while preserving the same steering/throttle/brake action contract.
|
|
15
|
+
- Add allocation-light track sampling helpers and a prepared sample-index lookup table so repeated `pointAt`/heading/curvature queries avoid binary-search and temporary-object churn on the common simulation paths.
|
|
16
|
+
- Reuse vehicle geometry, body AABB, swept AABB, and interpolated body-shape containers across collision and render paths instead of rebuilding geometry wrappers and axis objects every step.
|
|
17
|
+
- Reuse participant-interaction serialization for render snapshots and avoid repeated spread/object reconstruction in participant interaction resolution.
|
|
18
|
+
- Reduce per-step race/rules/timing churn by replacing transient race-order maps, steward review spreads, repeated inactive-steward state objects, and sector serialization maps with pooled or direct loop paths.
|
|
19
|
+
- Keep advanced/simulator-mode checks behind one helper so browser expert resets, red-flag release, collision damping, driver stabilization, and external state placement stay aligned with the documented `physicsMode` contract.
|
|
20
|
+
|
|
21
|
+
### Fixes And Hardening
|
|
22
|
+
|
|
23
|
+
- Preserve the resolved advanced physics mode when the browser expert adapter resets its environment, so expert-controlled browser runs do not silently fall back to arcade behavior.
|
|
24
|
+
- Keep unsupported browser and headless `physicsMode` values normalized to `arcade`, including explicit regression coverage for both surfaces.
|
|
25
|
+
- Carry optional `driverModel` metadata from driver or vehicle input into runtime car state for host-owned model/controller bookkeeping without adding a package-owned model loader.
|
|
26
|
+
- Tighten the environment performance characterization threshold for vector/object observation runs so ray-enabled physical-driver observations remain under the fixed local timing budget.
|
|
27
|
+
|
|
28
|
+
### Showcase And Tooling
|
|
29
|
+
|
|
30
|
+
- Add a playable-preview physics selector so the keyboard workbench can switch between arcade and advanced physics through the same documented query-parameter path as the rest of the preview.
|
|
31
|
+
- Add the `scripts/profile-hotspots.mjs` local profiling helper for advanced-mode race hot spots, with validated `--steps`, `--help`, and extra-argument handling.
|
|
32
|
+
- Split browser-smoke and runtime-benchmark argument parsing into focused helpers with direct unit coverage, and extend script coverage across consumer smoke, bundle-boundary, track-query benchmark, and profiler entrypoints.
|
|
33
|
+
- Keep the packed release contents focused on published package assets, docs, Python policy-server examples, source modules, public styles, and placeholder assets.
|
|
34
|
+
|
|
35
|
+
### Migration Notes
|
|
36
|
+
|
|
37
|
+
- No breaking host migration is required from `4.1.0`.
|
|
38
|
+
- Supported browser mounts, composable mounts, `@inventure71/paddockjs/environment`, `@inventure71/paddockjs/data`, and `@inventure71/paddockjs/placeholder` keep their documented public import contracts.
|
|
39
|
+
- Hosts should not depend on removed repository-local JavaScript training scripts or preview-only policy helper names. Use the documented environment API, custom model controller guide, or Python policy-server bridge for external training and policy integration.
|
|
40
|
+
|
|
41
|
+
### Verification Notes
|
|
42
|
+
|
|
43
|
+
- The final release gate is `npm run check:release`.
|
|
44
|
+
|
|
45
|
+
## 4.1.0
|
|
46
|
+
|
|
47
|
+
### Minor Changes
|
|
48
|
+
|
|
49
|
+
- Add a tiny pre-JS startup placeholder subpath and stylesheet for hosts that want an instant simulator loading surface before importing the full PaddockJS browser runtime. Also tighten the built-in component loading overlay contract across public mounted surfaces.
|
|
50
|
+
|
|
3
51
|
## 4.0.0
|
|
4
52
|
|
|
5
53
|
### Major Changes
|
package/INSTALL_AND_UPDATE.md
CHANGED
|
@@ -114,12 +114,24 @@ npm run check
|
|
|
114
114
|
Install a specific version when the host needs a controlled upgrade:
|
|
115
115
|
|
|
116
116
|
```bash
|
|
117
|
-
npm install @inventure71/paddockjs@4.
|
|
117
|
+
npm install @inventure71/paddockjs@4.2.0
|
|
118
118
|
npm run check
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
After updating, smoke-test the page that mounts the simulator. Browser behavior changes should be checked in the consuming host, because host CSS, container size, and route handling are outside the package.
|
|
122
122
|
|
|
123
|
+
### 4.2.0 Migration Notes
|
|
124
|
+
|
|
125
|
+
- No breaking host migration is required from `4.1.0`.
|
|
126
|
+
- Browser mounts, composable mounts, `@inventure71/paddockjs/environment`, `@inventure71/paddockjs/data`, and `@inventure71/paddockjs/placeholder` keep their documented public import contracts.
|
|
127
|
+
- Do not rely on repository-local JavaScript trainer scripts or preview-only policy helper names as package API. Local model experiments belong outside the package surface; production integrations should use the documented environment API, custom model controller guide, or Python policy-server bridge.
|
|
128
|
+
|
|
129
|
+
### 4.1.0 Migration Notes
|
|
130
|
+
|
|
131
|
+
- No breaking host migration is required from `4.0.0`.
|
|
132
|
+
- Hosts that want visible simulator startup UI before the full PaddockJS browser bundle downloads can render the new `@inventure71/paddockjs/placeholder` HTML helper with the optional `@inventure71/paddockjs/placeholder.css` stylesheet. This placeholder subpath is intentionally independent of PixiJS, simulator assets, root runtime CSS, and the browser mount. Static HTML hosts should generate the placeholder HTML during their build and copy the CSS into their static output; see [Startup Loading](docs/loading.md).
|
|
133
|
+
- Existing `mountF1Simulator()` and composable `mount*()` integrations keep their normal automatic package loading overlays after PaddockJS JavaScript starts.
|
|
134
|
+
|
|
123
135
|
### 4.0.0 Migration Notes
|
|
124
136
|
|
|
125
137
|
- Update Policy Runner HTTP servers for protocol version `2`. Cache `actionSpec`, `observationSpec`, configuration, `previousActionFields`, and `metricFields` from `/policy/reset`, then read model inputs from `body.driverIds[index]` plus aligned `body.vectors[index]`, `body.previousActions[index]`, and `body.metrics[index]` in `/policy/decide-batch`. Rich observation objects, schemas, snapshots, and track metadata are no longer sent on every policy-server decision.
|
|
@@ -145,6 +157,7 @@ The package repo owns its release process:
|
|
|
145
157
|
- `npm run check` runs docs checks, fast runtime tests, public type verification, dry-pack verification, packed-consumer install/build verification, the tracked showcase build, and a quick Chromium browser smoke test.
|
|
146
158
|
- `npm run check:release` runs the exhaustive release gate, including slow characterization tests and the full Chromium browser smoke matrix.
|
|
147
159
|
- `npm run consumer:smoke` packs the package, installs the tarball into a fresh temporary Vite app, and builds that app through public package imports.
|
|
160
|
+
- `npm run consumer:bundle-boundaries` packs the package, installs the tarball into a fresh temporary Vite app, and verifies the root browser import remains the CSS/asset-owning simulator bundle while `/placeholder`, `/data`, and `/environment` stay CSS-free or lightweight according to their documented roles.
|
|
148
161
|
- `npm run browser:smoke` builds `local-preview`, starts a local preview server, and checks desktop/mobile canvas rendering, overflow constraints, API buttons, and visual policy-runner stepping in Chromium. Use `npm run browser:smoke:quick` for the smaller local browser pass and `npm run browser:smoke:full` for the full matrix.
|
|
149
162
|
- `npm run changeset` records the next version bump and changelog note.
|
|
150
163
|
- `npm run version-packages` applies pending Changesets locally.
|
package/README.md
CHANGED
|
@@ -54,9 +54,40 @@ import '@inventure71/paddockjs/styles.css';
|
|
|
54
54
|
|
|
55
55
|
PaddockJS CSS is scoped under package mount/component roots and uses system font stacks. The package does not load Google Fonts or any other remote font. Hosts that want branded typography should load fonts in the host app.
|
|
56
56
|
|
|
57
|
+
## Startup Loading
|
|
58
|
+
|
|
59
|
+
`mountF1Simulator(root, options)` writes a lightweight package-owned HTML shell into `root` before it awaits PixiJS setup, asset loading, control binding, simulation creation, and the first canvas frame. That shell includes package loading overlays for the race controls, timing tower, race canvas, race-data panel, telemetry stack, and any other startup-capable package surface in the selected template. The overlays are removed only after the runtime has initialized and the initial readouts/frame are ready.
|
|
60
|
+
|
|
61
|
+
Composable hosts get the same behavior per mounted root: every public `simulator.mount*()` surface renders static package markup plus its own loading overlay before `await simulator.start()`.
|
|
62
|
+
|
|
63
|
+
This is a client-side startup shell, not server rendering. If a host wants visible content before the PaddockJS JavaScript bundle has downloaded and executed, use the tiny placeholder subpath and CSS:
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
import { createPaddockLoadingPlaceholder } from '@inventure71/paddockjs/placeholder';
|
|
67
|
+
import '@inventure71/paddockjs/placeholder.css';
|
|
68
|
+
|
|
69
|
+
root.innerHTML = createPaddockLoadingPlaceholder({
|
|
70
|
+
label: 'Loading simulator',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const loadSimulator = async () => {
|
|
74
|
+
const { mountF1Simulator } = await import('@inventure71/paddockjs');
|
|
75
|
+
await mountF1Simulator(root, { drivers, entries });
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
if ('requestIdleCallback' in window) {
|
|
79
|
+
window.requestIdleCallback(loadSimulator);
|
|
80
|
+
} else {
|
|
81
|
+
setTimeout(loadSimulator, 0);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`@inventure71/paddockjs/placeholder` does not import PixiJS, simulator assets, package runtime CSS, or the root browser mount. It is intended for the pre-JS/network gap. The full simulator mount replaces that placeholder and then uses the built-in package overlays while PixiJS and the race runtime finish booting. Static HTML hosts should run the placeholder helper in their build step and copy `@inventure71/paddockjs/placeholder.css` into their static output instead of expecting a plain browser page to resolve bare npm imports.
|
|
86
|
+
|
|
57
87
|
Start here:
|
|
58
88
|
|
|
59
89
|
- [Getting Started](docs/getting-started.md): install, browser mount, CSS, assets, host responsibilities, and container sizing.
|
|
90
|
+
- [Startup Loading](docs/loading.md): pre-JS placeholders, package loading overlays, and static-host build-time integration.
|
|
60
91
|
- [Data Contract](docs/data_contract.md): driver, entry, callback, rules, and option shapes.
|
|
61
92
|
- [Troubleshooting](docs/troubleshooting.md): common integration failures and supported checks.
|
|
62
93
|
|
|
@@ -146,11 +177,12 @@ npm run docs:check
|
|
|
146
177
|
npm run check
|
|
147
178
|
npm run check:release
|
|
148
179
|
npm run consumer:smoke
|
|
180
|
+
npm run consumer:bundle-boundaries
|
|
149
181
|
npm run browser:smoke:quick -- --skip-build
|
|
150
182
|
npm run showcase:dev
|
|
151
183
|
```
|
|
152
184
|
|
|
153
|
-
`npm run check` is the normal local gate: docs checks, fast runtime tests, public declarations, dry package contents, packed-package consumption in a fresh Vite app, the showcase build, and a quick Chromium smoke against the showcase. `npm run check:release` adds slow characterization tests and the full browser smoke matrix.
|
|
185
|
+
`npm run check` is the normal local gate: docs checks, fast runtime tests, public declarations, dry package contents, packed-package consumption in a fresh Vite app, packed subpath bundle-boundary checks, the showcase build, and a quick Chromium smoke against the showcase. `npm run check:release` adds slow characterization tests and the full browser smoke matrix.
|
|
154
186
|
|
|
155
187
|
## License
|
|
156
188
|
|
package/docs/architecture.md
CHANGED
|
@@ -281,6 +281,8 @@ Timing maintenance is also kept allocation-light now. Runtime timing writes in `
|
|
|
281
281
|
|
|
282
282
|
`src/simulation/vehicle/vehicleState.js` owns external state mutation from simulator and environment reset APIs. It rejects non-finite numeric partial state and resynchronizes advanced-mode velocity from speed/heading when callers do not provide an explicit velocity vector, so scenario placement and `resetDrivers()` cannot leave stale physics velocity behind.
|
|
283
283
|
|
|
284
|
+
Local model training experiments belong outside the committed package surface. The ignored `training-lab/` folder may hold local trainer scripts, checkpoints, model loaders, and research harnesses, but package modules, preview routes, public exports, published types, and consumer docs must stay focused on simulator/environment/display contracts.
|
|
285
|
+
|
|
284
286
|
`src/simulation/rules/pitLaneSpeedingSteward.js` owns pit-speed-limit review. `raceSimulation.js` calls it after authoritative race-state recalculation so it reads the same pit-lane part classification as snapshots and track-limit stewarding. The steward only checks speed-limited pit-lane parts (`fast-lane`, `working-lane`, service areas, and garage boxes), leaving pit-entry and pit-exit connector roads legal but not speed-limited.
|
|
285
287
|
|
|
286
288
|
Browser mounts generate a fresh procedural seed when `trackSeed` is omitted; explicit procedural track seeds are cached by seed plus resolved generation options so repeated mounts with the same procedural contract do not regenerate or rebuild the same model. The canonical generator owns both the default `race` profile and the smaller training profiles. Profile resolution lives beside the track model, merges `race` defaults, selected profile defaults, and explicit overrides, then feeds the same centerline, validation, start-straight, spatial-query, surface, and physics pipeline. Procedural generation starts from seeded connected coarse region masks, traces the outer boundary, smooths and warps the boundary into centerline controls, validates shape, clearance, local turn accumulation, length, and per-sample heading jumps, and retries with another region-derived control set instead of immediately falling back to an oval control ring when attempts fail.
|
|
@@ -340,7 +342,7 @@ Race completion is owned by `src/simulation/raceSimulation.js`. The simulation r
|
|
|
340
342
|
|
|
341
343
|
Composable hosts may choose where each package-owned component root is placed, but they still receive package-generated markup through the public mount functions. The controller marks each mounted root as an `f1-sim-component` styling scope so standalone pieces receive the same package variables as the all-in-one shell.
|
|
342
344
|
|
|
343
|
-
`src/styles.css` styles the generated shell, uses package-owned system font stacks, caps timing-tower width for readability, and owns the timing-list scroll behavior. Timing rows are compact content-sized grid rows stacked from the top, with `ui.timingEntryVerticalPadding` setting one shared pixel padding value above and below every entry, so rank positions do not stretch or redistribute when the number of entries changes. The timing tower owns its runtime interval-vs-leader-gap switch, while `F1SimulatorApp` reads both seconds and whole-lap gap values from the race snapshot and formats positive lap deficits as `+N` before seconds. The compact `Int`/`Gap` header toggle is a timing-tower style contract, not host CSS: the grid reserves a stable gap column, the header labels and toggle share one vertical center, the visible pill stays inside the header, and the clickable target remains `44px` without changing tower width. Fixed hidden timing-line creation, crossing timestamps, and seconds-gap calculation stay inside `src/simulation/timing/`. Sector-map surfaces read `lapTelemetry.sectorProgress` for bar fill and `lapTelemetry.liveSectors` for live active-sector time; the simulation owns those values so UI components do not infer active split state from DOM state. Future sectors are cleared by the simulation and ignored defensively by the renderer, so banner/sidebar sector nodes cannot keep stale timing text or yellow/purple/green performance classes after the active sector changes. Component templates include lightweight package-owned loading overlays; `F1SimulatorApp` removes them after
|
|
345
|
+
`src/styles.css` styles the generated shell, uses package-owned system font stacks, caps timing-tower width for readability, and owns the timing-list scroll behavior. Timing rows are compact content-sized grid rows stacked from the top, with `ui.timingEntryVerticalPadding` setting one shared pixel padding value above and below every entry, so rank positions do not stretch or redistribute when the number of entries changes. The timing tower owns its runtime interval-vs-leader-gap switch, while `F1SimulatorApp` reads both seconds and whole-lap gap values from the race snapshot and formats positive lap deficits as `+N` before seconds. The compact `Int`/`Gap` header toggle is a timing-tower style contract, not host CSS: the grid reserves a stable gap column, the header labels and toggle share one vertical center, the visible pill stays inside the header, and the clickable target remains `44px` without changing tower width. Fixed hidden timing-line creation, crossing timestamps, and seconds-gap calculation stay inside `src/simulation/timing/`. Sector-map surfaces read `lapTelemetry.sectorProgress` for bar fill and `lapTelemetry.liveSectors` for live active-sector time; the simulation owns those values so UI components do not infer active split state from DOM state. Future sectors are cleared by the simulation and ignored defensively by the renderer, so banner/sidebar sector nodes cannot keep stale timing text or yellow/purple/green performance classes after the active sector changes. Component templates include lightweight package-owned loading overlays that exist after package JavaScript mounts the shell but before PixiJS/runtime startup completes; `F1SimulatorApp` removes them only after the initial frame has rendered. `src/placeholder/index.js` and `src/placeholder.css` own the separate pre-root-import placeholder contract and must remain independent of `src/index.js`, PixiJS, simulator assets, `src/styles.css`, and browser app modules.
|
|
344
346
|
|
|
345
347
|
The host page should only provide:
|
|
346
348
|
|
|
@@ -18,7 +18,7 @@ This inventory maps package-owned UI surfaces to their shared bases, owner modul
|
|
|
18
18
|
| --- | --- | --- | --- | --- | --- |
|
|
19
19
|
| All-in-one shell | `mountF1Simulator()` | `src/ui/shellTemplate.js` | Composes race controls, optional external camera controls, timing tower, race canvas, telemetry stack, shell unsupported overlay | `F1SimulatorApp` | Owns `data-f1-simulator-shell`, workspace/grid classes, layout preset classes, and the package root styling scope. Not individually mounted by composable hosts. |
|
|
20
20
|
| Race controls | `mountRaceControls()` and all-in-one shell | `src/ui/raceControlsTemplate.js` | Component surface frame helper, `createSafetyCarControlMarkup({ compact: true })`, loading overlay, unsupported overlay | `controlStateRenderer.js` plus `F1SimulatorApp.bindControls()` | Includes title, kicker, safe backlink, safety-car button, and restart. The compact safety button has no standalone component wrapper. |
|
|
21
|
-
| Safety-car control | `mountSafetyCarControl()` and drawer/race-controls compact embed | `src/ui/raceControlsTemplate.js` | Component surface frame helper for standalone, same `data-safety-car` button and control-state renderer | `controlStateRenderer.js` plus `F1SimulatorApp.bindControls()` | Standalone variant gets `data-paddock-component="safety-car-control"
|
|
21
|
+
| Safety-car control | `mountSafetyCarControl()` and drawer/race-controls compact embed | `src/ui/raceControlsTemplate.js` | Component surface frame helper for standalone, loading overlay, unsupported overlay, same `data-safety-car` button and control-state renderer | `controlStateRenderer.js` plus `F1SimulatorApp.bindControls()` | Standalone variant gets `data-paddock-component="safety-car-control"`. Compact variants are plain subcontrols inside race controls or drawer toolbar. |
|
|
22
22
|
| Camera controls | `mountCameraControls()`, all-in-one external controls, embedded race-canvas controls, drawer toolbar | `src/ui/cameraControlsTemplate.js` | Component surface frame helper, shared `data-camera-mode`, zoom, banner mute, optional speed button, loading overlay, unsupported overlay | `controlStateRenderer.js`, `CameraController`, `F1SimulatorApp.bindControls()` | External variant adds `camera-controls--external`; embedded variant omits that class. Driver camera and simulation-speed buttons are option gated. |
|
|
23
23
|
| Timing tower | `mountTimingTower()`, all-in-one shell, embedded race canvas, drawer race canvas | `src/ui/timingTowerTemplate.js` | Component surface frame helper, race-control status banner, loading overlay, unsupported overlay, shared timing gap controls | `timingTowerRenderer.js`, `raceStatusRenderer.js`, `controlStateRenderer.js`, `F1SimulatorApp.observeLayoutResize()` | Embedded variants receive generated instance ids for `aria-controls`. `domBindings.js` exposes plural timing lists/header/status nodes and focused renderers fan out rows, lap counters, status banners, gap controls, and resize observation across every mounted tower owned by the same simulator. Header gap toggle may be hidden while controller APIs remain active. Width/proportions are package-owned and must not be tuned by host CSS. |
|
|
24
24
|
| Race-control status banner | Timing tower internal component | `src/ui/raceControlStatusBanner.js` | Timing tower status slot | `raceStatusRenderer.js` | Internal only. It has no public mount because it is a timing-tower status affordance, not a standalone component. |
|
|
@@ -27,14 +27,15 @@ This inventory maps package-owned UI surfaces to their shared bases, owner modul
|
|
|
27
27
|
| Steward message | Race canvas internal component | `src/ui/bannerTemplates.js` | Shared banner markup conventions | `stewardMessageController.js` | Internal top race-control message for warnings/penalties. No public mount because it depends on race-canvas layering. |
|
|
28
28
|
| Race-data panel | `mountRaceDataPanel()`, race canvas lower-third, drawer lower-third | `src/ui/bannerTemplates.js` | Component surface frame helper, selected driver readouts, optional race-data telemetry detail, loading overlay, unsupported overlay | `domBindings.js` grouped panel bindings, `raceDataBannerController.js`, `telemetryRenderer.js` for sector detail | Standalone variant adds `race-data-panel--standalone`. Embedded variants are clipped/layered by race canvas. Project and radio modes share the same panel; runtime swaps content/classes across every mounted panel owned by the simulator. |
|
|
29
29
|
| Telemetry sector banner | `mountTelemetrySectorBanner()` and optional race-canvas embed | `src/ui/bannerTemplates.js` | Component surface frame helper, sector-bar markup, loading overlay, unsupported overlay | `telemetryRenderer.js` | Independent broadcast lower-third style sector surface. It is separate from race-data telemetry detail and should only render when explicitly mounted or embedded. |
|
|
30
|
-
| Telemetry stack | `mountTelemetryPanel()` and drawer content | `src/ui/telemetryTemplates.js` | Component surface frame helper, telemetry core, sector progress, lap times, sector times, optional car/driver overview, unsupported overlay | `telemetryRenderer.js`, `carOverviewRenderer.js` when overview is included | The stack owns scrolling when constrained. It may include overview by default, but drawer content intentionally disables overview. |
|
|
30
|
+
| Telemetry stack | `mountTelemetryPanel()` and drawer content | `src/ui/telemetryTemplates.js` | Component surface frame helper, loading overlay, telemetry core, sector progress, lap times, sector times, optional car/driver overview, unsupported overlay | `telemetryRenderer.js`, `carOverviewRenderer.js` when overview is included | The stack owns scrolling when constrained. It may include overview by default, but drawer content intentionally disables overview. |
|
|
31
31
|
| Telemetry core | `mountTelemetryCore()` and telemetry stack | `src/ui/telemetryTemplates.js` | Telemetry module class helper, loading overlay, unsupported overlay | `telemetryRenderer.js` | Scalar selected-car telemetry only. It shares selected-code/name readouts with sector banner. |
|
|
32
32
|
| Telemetry sectors | `mountTelemetrySectors()` and telemetry stack | `src/ui/telemetryTemplates.js` | Telemetry module class helper, sector-bar markup, loading overlay, unsupported overlay | `telemetryRenderer.js` | Sector progress bars only. It shares sector bar selectors with race-data detail and sector banner. |
|
|
33
33
|
| Telemetry lap times | `mountTelemetryLapTimes()` and telemetry stack | `src/ui/telemetryTemplates.js` | Telemetry module class helper, loading overlay, unsupported overlay | `telemetryRenderer.js` | Current, last, and best lap table only. |
|
|
34
34
|
| Telemetry sector times | `mountTelemetrySectorTimes()` and telemetry stack | `src/ui/telemetryTemplates.js` | Telemetry module class helper, loading overlay, unsupported overlay | `telemetryRenderer.js` | Last/best sector table only. |
|
|
35
35
|
| Car/driver overview | `mountCarDriverOverview()` and optional telemetry stack embed | `src/ui/carOverviewTemplate.js` | Component surface frame helper, overview field slots, loading overlay, unsupported overlay | `domBindings.js` cached field bindings, `carOverviewRenderer.js` | Standalone and stack-embedded variants share identical markup. Runtime toggles vehicle vs driver fields without remounting and updates cached label/value bindings instead of querying each field during render. |
|
|
36
|
-
| Race telemetry drawer | `mountRaceTelemetryDrawer()` and complete preview template | `src/ui/telemetryDrawerTemplate.js` | Component surface frame helper, camera controls, compact safety-car control, race canvas with timing/data panel, telemetry stack, unsupported overlay | `F1SimulatorApp.setTelemetryDrawerOpen()`, `controlStateRenderer.js`, normal race/telemetry renderers | Higher-level mixed template. It intentionally owns toolbar placement, drawer ids, open/closed inert state, and responsive narrow drawer behavior. |
|
|
37
|
-
| Loading overlay | All startup-capable
|
|
36
|
+
| Race telemetry drawer | `mountRaceTelemetryDrawer()` and complete preview template | `src/ui/telemetryDrawerTemplate.js` | Component surface frame helper, loading overlay, camera controls, compact safety-car control, race canvas with timing/data panel, telemetry stack, unsupported overlay | `F1SimulatorApp.setTelemetryDrawerOpen()`, `controlStateRenderer.js`, normal race/telemetry renderers | Higher-level mixed template. It intentionally owns toolbar placement, drawer ids, open/closed inert state, and responsive narrow drawer behavior. |
|
|
37
|
+
| Loading overlay | All public startup-capable mounted surfaces, including all-in-one shell children and composable roots | `src/ui/templateUtils.js` | `createLoadingMarkup(label)` | `F1SimulatorApp.completeComponentLoading()` | Removed after startup after the initial frame. Component labels remain surface-specific for accessibility. Pre-JS placeholders are rendered by the host before package runtime starts, not by `F1SimulatorApp`. |
|
|
38
|
+
| Pre-JS startup placeholder | `@inventure71/paddockjs/placeholder` and `@inventure71/paddockjs/placeholder.css` | `src/placeholder/index.js`, `src/placeholder.css` | Escaped inert HTML helper, optional tiny CSS start-light animation | Host page before root simulator import | Covers the network/import gap before the root package can render. It must stay independent of PixiJS, simulator assets, root runtime CSS, and app modules. |
|
|
38
39
|
| Unsupported-size overlay | Public mount roots, shell, drawer, race/data/telemetry surfaces | `src/ui/templateUtils.js` | `createUnsupportedSizeMarkup(label)` | `installLayoutSupport()` | Display is driven by measured support state. Minimum size thresholds remain centralized in `layoutSupport.js`. |
|
|
39
40
|
|
|
40
41
|
## Local Preview Variants
|
|
@@ -34,6 +34,8 @@ await simulator.start();
|
|
|
34
34
|
|
|
35
35
|
Controller methods are the canonical composable style. The standalone mount helper exports exist for compatibility, but new host code should prefer `simulator.mountRaceCanvas(root)` and the matching controller methods.
|
|
36
36
|
|
|
37
|
+
Each `mount*()` call writes lightweight static package markup into that root immediately and includes a package-owned loading overlay for the mounted surface. `await simulator.start()` then initializes the shared PixiJS/simulation runtime and removes those overlays after assets, controls, initial DOM readouts, and the first frame are ready. Mount all required surfaces before `start()` so the runtime can bind one coherent set of package-owned controls and readouts.
|
|
38
|
+
|
|
37
39
|
## Available Surfaces
|
|
38
40
|
|
|
39
41
|
- `mountRaceControls(root)`
|
package/docs/data_contract.md
CHANGED
|
@@ -1203,4 +1203,8 @@ Composable controllers additionally expose the canonical composable mounting API
|
|
|
1203
1203
|
- `querySelector(selector)` / `querySelectorAll(selector)`: search across the mounted package-owned composable roots. These exist for integration tests and advanced host glue; ordinary hosts should prefer explicit controller methods and mounted component roots.
|
|
1204
1204
|
- `start()`: initializes PixiJS, binds mounted controls, and starts the simulation loop.
|
|
1205
1205
|
|
|
1206
|
-
Mount component roots before calling `start()`. If a component is not mounted, the runtime skips that UI surface instead of requiring hidden placeholder DOM.
|
|
1206
|
+
Mount component roots before calling `start()`. If a component is not mounted, the runtime skips that UI surface instead of requiring hidden placeholder DOM. Every public mounted surface renders lightweight static package markup and a surface-specific `data-paddock-loading` overlay immediately. `start()` removes those overlays only after PixiJS, assets, controls, initial DOM readouts, and the first frame have initialized. If `restart(nextOptions)` is called before `start()`, mounted component markup is refreshed from the new resolved options so copy, component visibility, driver data, and theme changes do not leave stale pre-start HTML behind.
|
|
1207
|
+
|
|
1208
|
+
This loading overlay is the package's client-side startup state. It begins after the PaddockJS JavaScript bundle has executed and a mount function has run. Hosts that need an instant placeholder before package JavaScript loads should render host-owned fallback HTML/CSS around or inside the mount root, then let `mountF1Simulator()` or the composable `mount*()` calls replace that root content when the package starts.
|
|
1209
|
+
|
|
1210
|
+
For a package-owned pre-JS placeholder, import `createPaddockLoadingPlaceholder()` from `@inventure71/paddockjs/placeholder` and the optional tiny stylesheet from `@inventure71/paddockjs/placeholder.css`. That subpath is intentionally separate from the root browser mount and does not import PixiJS, simulator assets, package runtime CSS, or `F1SimulatorApp`.
|
package/docs/getting-started.md
CHANGED
|
@@ -38,6 +38,38 @@ if (root) {
|
|
|
38
38
|
|
|
39
39
|
Use the root package only for browser mounts and browser helper exports. It imports package CSS and bundled simulator assets.
|
|
40
40
|
|
|
41
|
+
## Startup Loading
|
|
42
|
+
|
|
43
|
+
`mountF1Simulator()` replaces the host root with a lightweight PaddockJS shell immediately after the package JavaScript starts running. The shell is normal HTML/CSS with package loading overlays; the PixiJS renderer, simulator runtime, textures, controls, and initial readouts are initialized afterward. The mount promise resolves only after that runtime initialization is complete.
|
|
44
|
+
|
|
45
|
+
For the fastest visible first paint, render the tiny placeholder before loading the full simulator bundle:
|
|
46
|
+
|
|
47
|
+
```html
|
|
48
|
+
<section class="simulator-section">
|
|
49
|
+
<div id="f1-simulator-root"></div>
|
|
50
|
+
</section>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
import { createPaddockLoadingPlaceholder } from '@inventure71/paddockjs/placeholder';
|
|
55
|
+
import '@inventure71/paddockjs/placeholder.css';
|
|
56
|
+
|
|
57
|
+
const root = document.getElementById('f1-simulator-root');
|
|
58
|
+
root.innerHTML = createPaddockLoadingPlaceholder({
|
|
59
|
+
label: 'Loading simulator',
|
|
60
|
+
detail: 'Preparing race control',
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const { mountF1Simulator } = await import('@inventure71/paddockjs');
|
|
64
|
+
await mountF1Simulator(root, { drivers, entries });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`@inventure71/paddockjs/placeholder` is CSS-free JavaScript and `@inventure71/paddockjs/placeholder.css` is a standalone tiny stylesheet. They do not import PixiJS, the simulator runtime, bundled assets, or the full package stylesheet. The default placeholder uses the same start-light idea as the simulator loading overlay. Pass `variant: 'custom'`, `className`, `detail`, or safe `attributes` when the host wants to layer its own overlay while keeping the same minimal helper contract.
|
|
68
|
+
|
|
69
|
+
That placeholder covers the time before the full PaddockJS bundle executes. Once the bundle runs, PaddockJS owns the root markup and shows its package loading overlays until the first real simulator frame is ready.
|
|
70
|
+
|
|
71
|
+
Plain static HTML pages cannot resolve bare npm imports such as `@inventure71/paddockjs/placeholder` directly in the browser without a bundler or import map. Static hosts should run `createPaddockLoadingPlaceholder()` in the site build script, inject the generated HTML into the static page, and copy `@inventure71/paddockjs/placeholder.css` into the static output. See [Startup Loading](loading.md) for the bundled and static-host patterns.
|
|
72
|
+
|
|
41
73
|
## CSS
|
|
42
74
|
|
|
43
75
|
Most browser bundlers consume the root package stylesheet automatically. If your host build does not, import the stylesheet explicitly from a browser entry:
|
|
@@ -70,6 +102,7 @@ If a package surface is constrained below its supported size, PaddockJS shows an
|
|
|
70
102
|
## Where To Go Next
|
|
71
103
|
|
|
72
104
|
- Use [Composable Layouts](composable-layouts.md) when the host needs separate package-owned surfaces.
|
|
105
|
+
- Use [Startup Loading](loading.md) when the host needs instant first paint, static HTML integration, or a clearer split between placeholders and runtime overlays.
|
|
73
106
|
- Use [Theming](theming.md) for runtime light/dark sync and token customization.
|
|
74
107
|
- Use [Data Contract](data_contract.md) for full driver, entry, rule, UI, callback, and asset option shapes.
|
|
75
108
|
- Use [Troubleshooting](troubleshooting.md) when a host build or browser smoke fails.
|
package/docs/index.md
CHANGED
|
@@ -7,6 +7,7 @@ Code snippets in the documentation are illustrative host integration fragments u
|
|
|
7
7
|
Start with the consumer task docs:
|
|
8
8
|
|
|
9
9
|
- [Getting Started](getting-started.md): install, browser mount, package CSS, bundled assets, host responsibilities, and container sizing.
|
|
10
|
+
- [Startup Loading](loading.md): pre-JS placeholders, package loading overlays, static-host build-time integration, and unsupported-size placeholders.
|
|
10
11
|
- [Composable Layouts](composable-layouts.md): building host layouts from package-owned simulator surfaces.
|
|
11
12
|
- [Headless Environment](headless-environment.md): browser-free environment imports, expert-mode boundary, and basic stepping.
|
|
12
13
|
- [Data Helpers](data-helpers.md): CSS-free data/tooling imports and procedural track helpers.
|
|
@@ -25,16 +26,17 @@ Reference docs:
|
|
|
25
26
|
- [Custom Model Controller Guide](custom_model_controller.md): how to wrap a trained model as a batched driver controller for browser playback or headless loops.
|
|
26
27
|
- [Architecture](architecture.md): module ownership and data/control flow.
|
|
27
28
|
- [Component Inventory](component_inventory.md): package-owned UI surfaces, shared bases, derived/mixed variants, and remaining intentional duplication.
|
|
29
|
+
- [Testing Reliability Guide](testing-reliability-guide.md): risk-driven test selection, behavior maps, required gates, and audit reporting standards.
|
|
28
30
|
- [Data Model Notes](data_model.md): lower-level simulator data model notes kept with package docs.
|
|
29
31
|
- [Learnings](learnings.md): implementation lessons and layout verification rules learned from simulator integration issues.
|
|
30
32
|
|
|
31
33
|
Common paths:
|
|
32
34
|
|
|
33
|
-
- Installing PaddockJS into a browser host: read [Getting Started](getting-started.md), then [Data Contract](data_contract.md) for full option shapes.
|
|
35
|
+
- Installing PaddockJS into a browser host: read [Getting Started](getting-started.md), [Startup Loading](loading.md), then [Data Contract](data_contract.md) for full option shapes.
|
|
34
36
|
- Upgrading an existing browser host from 2.x-era usage: read [Upgrading Hosts to 4.x](upgrading-hosts-to-3.md), then [Troubleshooting](troubleshooting.md) if the host build fails.
|
|
35
37
|
- Building a package-owned composable layout: read [Composable Layouts](composable-layouts.md), then the sizing and UI options in [Data Contract](data_contract.md).
|
|
36
38
|
- Enabling pits, penalties, tire requirements, safety car, or stalled off-track DNF: read [Rules](rules.md) first. Pit stops require `rules.modules.pitStops.enabled`; `tireStrategy` alone only controls compounds, tire-requirement stewarding, and pit target choices.
|
|
37
39
|
- Connecting a trained model: read [Headless Environment](headless-environment.md), [Bring Your Own Model](training.md), then [Custom Model Controller Guide](custom_model_controller.md). PaddockJS owns observations, actions, specs, scenarios, and browser playback; the host owns the model, reward, storage, and training framework.
|
|
38
|
-
- Changing internals: read [Architecture](architecture.md) before editing source so new code lands in the feature-owned module instead of a facade or compatibility barrel.
|
|
40
|
+
- Changing internals: read [Architecture](architecture.md) before editing source so new code lands in the feature-owned module instead of a facade or compatibility barrel. Read [Testing Reliability Guide](testing-reliability-guide.md) before adding or changing tests.
|
|
39
41
|
|
|
40
42
|
When simulator behavior changes, update the relevant doc in this folder in the same change.
|
package/docs/loading.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Startup Loading
|
|
2
|
+
|
|
3
|
+
PaddockJS has two different startup loading surfaces. They solve different timing problems and should not be treated as interchangeable.
|
|
4
|
+
|
|
5
|
+
## The Two Phases
|
|
6
|
+
|
|
7
|
+
| Phase | When it can appear | Owner | Purpose |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| Pre-JS placeholder | Before the full PaddockJS browser bundle has downloaded, parsed, and imported | Host page, using the optional package placeholder helper/CSS | Give the user immediate lightweight visual feedback during the network/import gap |
|
|
10
|
+
| Package loading overlays | After `mountF1Simulator()` or a composable `mount*()` call starts | PaddockJS runtime | Cover PixiJS setup, asset loading, control binding, simulation creation, readout initialization, and the first real frame |
|
|
11
|
+
|
|
12
|
+
The pre-JS placeholder exists because PaddockJS cannot render anything before PaddockJS code exists on the page. The package loading overlays exist because, once the package has started, the runtime still needs time to build the simulator.
|
|
13
|
+
|
|
14
|
+
## Phase 1: Pre-JS Placeholder
|
|
15
|
+
|
|
16
|
+
Use the optional placeholder subpath when a host wants visible simulator UI before importing the full browser runtime:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
import { createPaddockLoadingPlaceholder } from '@inventure71/paddockjs/placeholder';
|
|
20
|
+
import '@inventure71/paddockjs/placeholder.css';
|
|
21
|
+
|
|
22
|
+
root.innerHTML = createPaddockLoadingPlaceholder({
|
|
23
|
+
label: 'Loading simulator',
|
|
24
|
+
detail: 'Preparing race control',
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`@inventure71/paddockjs/placeholder` is intentionally separate from the root package. It does not import PixiJS, simulator assets, package runtime CSS, `F1SimulatorApp`, or the browser mount. The stylesheet at `@inventure71/paddockjs/placeholder.css` is a tiny standalone stylesheet for the default start-light placeholder.
|
|
29
|
+
|
|
30
|
+
The helper returns inert escaped HTML. It does not mount the simulator, register event listeners, fetch assets, or start any timers. The default `lights` variant uses CSS animation only.
|
|
31
|
+
|
|
32
|
+
## Bundled Browser Hosts
|
|
33
|
+
|
|
34
|
+
In Vite, Rollup, Webpack, or another browser bundler, render the placeholder first, then dynamically import the full simulator:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import { createPaddockLoadingPlaceholder } from '@inventure71/paddockjs/placeholder';
|
|
38
|
+
import '@inventure71/paddockjs/placeholder.css';
|
|
39
|
+
|
|
40
|
+
const root = document.getElementById('f1-simulator-root');
|
|
41
|
+
|
|
42
|
+
root.innerHTML = createPaddockLoadingPlaceholder({
|
|
43
|
+
label: 'Loading simulator',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const startSimulator = async () => {
|
|
47
|
+
const { mountF1Simulator } = await import('@inventure71/paddockjs');
|
|
48
|
+
await mountF1Simulator(root, { drivers, entries });
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
if ('requestIdleCallback' in window) {
|
|
52
|
+
window.requestIdleCallback(startSimulator);
|
|
53
|
+
} else {
|
|
54
|
+
setTimeout(startSimulator, 0);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The dynamic root import lets the page paint the placeholder before paying for the full browser simulator bundle. The full mount replaces the placeholder root content when PaddockJS starts.
|
|
59
|
+
|
|
60
|
+
## Static HTML Hosts
|
|
61
|
+
|
|
62
|
+
Plain static HTML pages cannot resolve bare npm imports such as `@inventure71/paddockjs/placeholder` directly in the browser unless the page also provides a bundler output or import map. Do not add a runtime bundling step only to render the placeholder.
|
|
63
|
+
|
|
64
|
+
For static hosts with a build script, run the helper at build time and inject the generated HTML into the static page:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
68
|
+
import { createRequire } from 'node:module';
|
|
69
|
+
import { dirname } from 'node:path';
|
|
70
|
+
import { createPaddockLoadingPlaceholder } from '@inventure71/paddockjs/placeholder';
|
|
71
|
+
|
|
72
|
+
const require = createRequire(import.meta.url);
|
|
73
|
+
|
|
74
|
+
const placeholderHtml = createPaddockLoadingPlaceholder({
|
|
75
|
+
label: 'Loading simulator',
|
|
76
|
+
detail: 'Preparing race preview',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const cssSource = require.resolve('@inventure71/paddockjs/placeholder.css');
|
|
80
|
+
const cssTarget = 'dist/f1-simulator/paddock-placeholder.css';
|
|
81
|
+
|
|
82
|
+
mkdirSync(dirname(cssTarget), { recursive: true });
|
|
83
|
+
copyFileSync(cssSource, cssTarget);
|
|
84
|
+
|
|
85
|
+
const html = readFileSync('projects.html', 'utf8')
|
|
86
|
+
.replace('<!-- paddock-placeholder -->', placeholderHtml)
|
|
87
|
+
.replace(
|
|
88
|
+
'</head>',
|
|
89
|
+
' <link rel="stylesheet" href="/f1-simulator/paddock-placeholder.css">\n</head>',
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
writeFileSync('dist/projects.html', html);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
That pattern keeps the first paint static and cheap while avoiding manual markup drift. The HTML still comes from the package helper, and the CSS still comes from the package stylesheet.
|
|
96
|
+
|
|
97
|
+
If a static host cannot run the helper during its build, copying the generated placeholder markup contract is acceptable as a fallback, but it is weaker. Manual markup can drift if the package changes the placeholder structure in a later release.
|
|
98
|
+
|
|
99
|
+
## Phase 2: Package Loading Overlays
|
|
100
|
+
|
|
101
|
+
After PaddockJS JavaScript starts, `mountF1Simulator(root, options)` synchronously writes a lightweight package shell into the mount root. The shell includes package-owned loading overlays for startup-capable surfaces such as the race canvas, controls, timing tower, race-data panel, telemetry stack, and composable component roots.
|
|
102
|
+
|
|
103
|
+
Composable hosts get the same behavior per mounted surface:
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
const simulator = createPaddockSimulator(options);
|
|
107
|
+
|
|
108
|
+
simulator.mountRaceCanvas(canvasRoot);
|
|
109
|
+
simulator.mountTimingTower(timingRoot);
|
|
110
|
+
simulator.mountTelemetryPanel(telemetryRoot);
|
|
111
|
+
|
|
112
|
+
await simulator.start();
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Each `mount*()` call writes static package markup and a surface-specific `data-paddock-loading` overlay immediately. `start()` removes those overlays only after PixiJS, assets, controls, initial DOM readouts, and the first frame have initialized.
|
|
116
|
+
|
|
117
|
+
These overlays are automatic. Hosts should not recreate them, query them for simulator state, or patch package internals to hide them. If a host needs a different pre-PaddockJS first paint, use the phase-1 placeholder around or inside the same root before calling the package mount.
|
|
118
|
+
|
|
119
|
+
## Replacement Flow
|
|
120
|
+
|
|
121
|
+
A typical lazy startup flow is:
|
|
122
|
+
|
|
123
|
+
1. Host HTML/CSS paints the page and optional pre-JS placeholder.
|
|
124
|
+
2. Host code imports the full PaddockJS browser bundle.
|
|
125
|
+
3. `mountF1Simulator()` or composable `mount*()` calls replace the placeholder with package startup markup.
|
|
126
|
+
4. PaddockJS shows package loading overlays while runtime setup finishes.
|
|
127
|
+
5. PaddockJS removes those overlays after the first real simulator frame is ready.
|
|
128
|
+
|
|
129
|
+
The pre-JS placeholder and package overlays can look similar, but they are intentionally separate. The first is a host-rendered shell for the network/import gap. The second is package runtime UI for simulator boot.
|
|
130
|
+
|
|
131
|
+
## What Not To Do
|
|
132
|
+
|
|
133
|
+
- Do not expect a plain static HTML page to resolve `@inventure71/paddockjs/placeholder` as a browser import without a bundler or import map.
|
|
134
|
+
- Do not eagerly import the root `@inventure71/paddockjs` package just to show a loading screen; that defeats the payload split.
|
|
135
|
+
- Do not copy simulator assets or PixiJS into the pre-JS placeholder.
|
|
136
|
+
- Do not manually maintain copied placeholder markup when the host has a build step that can call `createPaddockLoadingPlaceholder()`.
|
|
137
|
+
- Do not style package runtime internals such as `.start-lights`, `.timing-list`, or `.race-data-panel` from host CSS. Size the host root and let PaddockJS own runtime layout.
|
|
138
|
+
|
|
139
|
+
## Related Placeholders
|
|
140
|
+
|
|
141
|
+
PaddockJS also shows an `Unsupported size` placeholder when a shell or component is constrained below its supported bounds. That is not a startup loader. It is a layout safety state that tells the host to fix the container size rather than letting package controls overlap or clip.
|
package/docs/system_specs.md
CHANGED
|
@@ -52,6 +52,7 @@ Root package exports:
|
|
|
52
52
|
| --- | --- | --- |
|
|
53
53
|
| Browser mounts | `mountF1Simulator`, `createPaddockSimulator` | all-in-one shell or composable package-owned UI surfaces |
|
|
54
54
|
| Composable helper mounts | `mountRaceControls`, `mountCameraControls`, `mountSafetyCarControl`, `mountTimingTower`, `mountRaceCanvas`, `mountTelemetryPanel`, `mountTelemetryCore`, `mountTelemetrySectors`, `mountTelemetrySectorBanner`, `mountTelemetryLapTimes`, `mountTelemetrySectorTimes`, `mountRaceTelemetryDrawer`, `mountCarDriverOverview`, `mountRaceDataPanel` | function-call wrappers around a composable simulator controller |
|
|
55
|
+
| Startup placeholder | `createPaddockLoadingPlaceholder` from `@inventure71/paddockjs/placeholder`, plus `@inventure71/paddockjs/placeholder.css` | optional pre-JS loading placeholder that does not import PixiJS, simulator assets, root runtime CSS, or the browser mount |
|
|
55
56
|
| Data helpers | `DriverData`, `VehicleData`, `CHAMPIONSHIP_ENTRY_BLUEPRINTS`, `DEMO_PROJECT_DRIVERS`, `buildChampionshipDriverGrid`, `formatDriverNumber`, `normalizeSimulatorDrivers` | demo data, host entry normalization, and rating helper construction |
|
|
56
57
|
| Theme helpers | `DEFAULT_PADDOCK_THEME`, `PADDOCK_THEME_CSS_VARIABLES`, `PADDOCK_THEME_TOKEN_KEYS`, `resolvePaddockTheme`, `applyPaddockTheme` | host-side theme preview/sync code without copying package token names |
|
|
57
58
|
| Package constants | `DEFAULT_F1_SIMULATOR_ASSETS`, `PADDOCK_SIMULATOR_PRESETS` | inspect bundled asset mapping and UI preset defaults |
|
|
@@ -66,6 +67,13 @@ Data subpath exports:
|
|
|
66
67
|
| `createProceduralTrack` | CSS-free procedural track generation helper |
|
|
67
68
|
| `kphToSimSpeed`, `simSpeedToKph` | CSS-free speed conversion helpers |
|
|
68
69
|
|
|
70
|
+
Placeholder subpath exports:
|
|
71
|
+
|
|
72
|
+
| Export | Use |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| `createPaddockLoadingPlaceholder(options)` | Generate inert, escaped startup placeholder HTML for the network/import gap before the root simulator bundle runs. |
|
|
75
|
+
| `PaddockLoadingPlaceholderOptions`, `PaddockLoadingPlaceholderVariant` | TypeScript shapes for host placeholder configuration. |
|
|
76
|
+
|
|
69
77
|
Environment subpath exports:
|
|
70
78
|
|
|
71
79
|
| Export | Use |
|
|
@@ -263,13 +271,15 @@ Returned controller:
|
|
|
263
271
|
- Composable mounting can embed the timing tower directly inside the race canvas with `mountRaceCanvas(root, { includeTimingTower: true })`.
|
|
264
272
|
- The race canvas is required before `start()` because PixiJS needs a canvas host.
|
|
265
273
|
- Mount component roots before calling `start()`. A pre-start `restart(nextOptions)` re-resolves options and refreshes already mounted component markup, so non-asset changes such as title, kicker, UI visibility, theme, drivers, entries, seed, or track seed are reflected before `start()` binds the runtime.
|
|
274
|
+
- `mountF1Simulator()` and each composable `mount*()` call must synchronously write lightweight package HTML before awaiting runtime initialization. Those startup templates may contain controls/readout placeholders, but they must not require PixiJS, texture loading, race stepping, or host-provided hidden DOM to be visible.
|
|
266
275
|
- Timing tower, telemetry, controls, and race-data panels are optional from a runtime safety perspective; omitted panels simply do not render their readouts.
|
|
267
276
|
- Timing tower entries are compact content-sized rows stacked from the top of the timing list. Row vertical position must be based on rank/index, never distributed by available height or total entry count. `ui.timingEntryVerticalPadding` defaults to `5` and applies that pixel value above and below every row entry.
|
|
268
277
|
- Timing tower entries display team icons. `ui.timingGapMode` sets the initial display to interval-to-car-ahead timing or direct gap-to-leader timing, and the controller can change it at runtime with `setTimingGapMode()`, `getTimingGapMode()`, or `toggleTimingGapMode()`. The tower shows one compact `Int`/`Gap` header toggle by default. That toggle must stay aligned with the other timing header labels, preserve a practical `44px` target, draw active/focus treatment inside the timing header rather than outside the column, and never change the timing board width. `ui.timingGapModeToggle: false` hides only the manual header affordance; it must not disable the controller API. Seconds gaps are calculated from hidden timing-line crossings, and whole-lap deficits display as `+N`.
|
|
269
278
|
- Snapshots expose calibrated display units through `speedKph`, `distanceMeters`, and `gapMeters`; internal physics remains in simulator units. Public timer, lap-time, sector-time, gap-time, penalty-time, and service-countdown values are seconds.
|
|
270
279
|
- Snapshots expose automatic three-sector track metadata through `track.sectors` and per-car lap/sector timing through `car.lapTelemetry`, including completed current-lap sector splits before the active sector, live active-sector elapsed time, per-sector progress, and sector performance classes for overall-best, personal-best, and slower completed sector times. Future-sector timing/progress entries are cleared so banner and sidebar telemetry cannot display stale split values from another lap or state.
|
|
271
280
|
- Entries can include optional `team` metadata. Team color defaults to car color when omitted.
|
|
272
|
-
- Mounted package surfaces show a package-owned red start-light loading overlay until `start()` finishes PixiJS, asset, control,
|
|
281
|
+
- Mounted package surfaces show a package-owned red start-light loading overlay until `start()` finishes PixiJS, asset, control, initial readout, and first-frame initialization. `F1SimulatorApp.completeComponentLoading()` marks the owning `data-paddock-component` as loaded and removes `data-paddock-loading` nodes after the initial frame is rendered.
|
|
282
|
+
- Package loading overlays are a post-JavaScript client startup state, not a server-rendered skeleton. Before the root PaddockJS bundle has downloaded, parsed, and called a mount function, only pre-existing HTML/CSS can paint. The optional `@inventure71/paddockjs/placeholder` subpath and `@inventure71/paddockjs/placeholder.css` stylesheet are the package-owned phase-1 contract for that gap. They must stay independent of PixiJS, simulator assets, root package CSS, app runtime modules, and browser mount side effects.
|
|
273
283
|
- `preset` is a preset-first API. Presets are resolved before explicit host overrides so hosts can use `dashboard`, `timing-overlay`, `compact-race`, or `full-dashboard` as a starting point and still override specific `ui` or `theme` fields.
|
|
274
284
|
- `theme` is the public sizing/color contract. It resolves semantic package-owned tokens into complete light/dark themes, supports named derivative theme packages through `theme.themes`, selects the active package with `theme.use`, applies component-specific packages through `theme.componentThemes`, and accepts team selectors through `theme.teamThemes` or `entries[*].team.theme`. Component theme keys accept package component ids such as `timing-tower` and camelCase aliases such as `timingTower`; `selectedDriverPanel` targets both selected-driver package surfaces. Selected-driver surfaces use the selected team's theme by default when one is available while structural controls keep the active global theme unless explicitly overridden. Unknown theme tokens or component slots are ignored, one-sided light/dark token overrides generate and cache the opposite mode, and theme plus driver/team colors are validated before they are written to CSS variables. Legacy aliases such as `accentColor`, `greenColor`, and `yellowColor` remain migration aliases for the new semantic tokens.
|
|
275
285
|
- `setTheme(theme)`, `setThemeMode(mode)`, and `syncThemeFrom(element, options)` are runtime presentation APIs. They must resolve through the same theme normalizer used at mount time, reapply CSS variables to every package-owned mounted root, and must not call `restart()` or replace race state. Existing simulation state, timing order, selected driver, active penalties, camera state, speed setting, and pit intent state remain owned by the running app. `syncThemeFrom()` applies immediately, watches the configured attribute with `MutationObserver` when available, maps host attribute values through `options.map`, and returns a cleanup function.
|
|
@@ -357,7 +367,7 @@ Full public race snapshots include `car.trackState` as the serialized car-center
|
|
|
357
367
|
- `pixi.js` available through the package dependency graph.
|
|
358
368
|
|
|
359
369
|
Raw Node imports of the package root are not a supported runtime check because the browser component entry imports CSS and image assets. The `@inventure71/paddockjs/environment` subpath is the supported browser-free import path for headless JavaScript training.
|
|
360
|
-
The
|
|
370
|
+
The package exposes a JSON-serializable worker protocol wrapper so external processes can bridge to the JavaScript environment without PaddockJS choosing Python, Gymnasium, PettingZoo, model storage, training algorithms, checkpoint formats, or training infrastructure.
|
|
361
371
|
|
|
362
372
|
## Verification
|
|
363
373
|
|
|
@@ -372,9 +382,12 @@ Expected:
|
|
|
372
382
|
- Fast Vitest tests pass in the normal local gate. Slow characterization tests run under `npm run check:release`.
|
|
373
383
|
- `npm pack --dry-run` succeeds and includes source files plus bundled assets.
|
|
374
384
|
- A packed tarball installs and builds inside a fresh temporary Vite consumer app.
|
|
385
|
+
- Packed subpath bundle-boundary checks verify that the root import remains the CSS/asset-owning browser simulator bundle while `/placeholder`, `/data`, and `/environment` stay CSS-free or lightweight according to their documented roles.
|
|
375
386
|
- The tracked showcase host builds.
|
|
376
387
|
- The quick Chromium browser smoke verifies showcase canvas rendering, overflow constraints, one public API action, and live customization theme switching. The release browser smoke verifies the desktop/mobile matrix, package-panel overflow constraints, customization route interactions, public API buttons, and visual policy-runner stepping across generation and race configurations.
|
|
377
388
|
|
|
389
|
+
Use [Testing Reliability Guide](testing-reliability-guide.md) to choose the smallest behavior-focused proof for a change before relying on the broad package gate. The guide is authoritative for mapping package/API, simulation, environment, browser, performance, and docs changes to focused tests and required broader verification.
|
|
390
|
+
|
|
378
391
|
For internal runtime-efficiency development only, also run:
|
|
379
392
|
|
|
380
393
|
```bash
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Testing Reliability Guide
|
|
2
|
+
|
|
3
|
+
PaddockJS reliability work is risk-driven. Do not add tests for coverage vanity. Add or change tests when they protect a package contract, a simulator state transition, a browser lifecycle path, or a performance invariant that can silently regress.
|
|
4
|
+
|
|
5
|
+
## Confidence Model
|
|
6
|
+
|
|
7
|
+
Use the smallest verification layer that proves the behavior, then run the broader gate before claiming package quality.
|
|
8
|
+
|
|
9
|
+
- Unit tests in `src/__tests__/` prove deterministic simulation, data normalization, sensor math, controller loops, and focused UI rendering helpers.
|
|
10
|
+
- Public type tests in `src/__tests__/publicApi.types.ts` prove the TypeScript consumer contract for root, `/data`, `/environment`, and `/placeholder` imports.
|
|
11
|
+
- `npm run consumer:smoke` proves the packed tarball installs and builds in a fresh Vite consumer through public package imports.
|
|
12
|
+
- `npm run consumer:bundle-boundaries` proves the packed root browser import remains the CSS/asset-owning simulator bundle while `/placeholder`, `/data`, and `/environment` stay CSS-free or lightweight according to their documented roles.
|
|
13
|
+
- `npm run showcase:ci` proves the tracked browser showcase still builds.
|
|
14
|
+
- `npm run browser:smoke:quick -- --skip-build` proves the built showcase can mount, paint a nonblank canvas, avoid key overflow regressions, exercise public controls, and keep live customization paths working.
|
|
15
|
+
- `npm run browser:smoke:full -- --skip-build` is required for broad browser/showcase/layout behavior and release handoff.
|
|
16
|
+
- `npm run benchmark:runtime -- --profile=standard --verify --json` proves simulation, sensor, rendering-data, snapshot, DOM-readout, and compact-transport performance contracts.
|
|
17
|
+
|
|
18
|
+
## Change Matrix
|
|
19
|
+
|
|
20
|
+
| Change area | Required focused proof | Required broader proof |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| Public root, `/data`, `/environment`, or `/placeholder` API/types | `npm run types:check` plus a public API type assertion when the contract changes | `npm run check` |
|
|
23
|
+
| Package install, exports, files, CSS/assets, subpath bundle boundaries, or build assumptions | `npm run pack:dry`, `npm run consumer:smoke`, or `npm run consumer:bundle-boundaries` | `npm run check` |
|
|
24
|
+
| Race rules, ordering, DRS, starts, safety car, red flag, pits, penalties, collisions, or finish/classification | Focused Vitest file for the changed rule path | `npm run check`; use `npm run check:release` for broad behavior |
|
|
25
|
+
| Track geometry, query index, wheel surfaces, runoff, contact patches, or sensor rays | Focused geometry/sensor tests plus benchmark verification when hot paths change | `npm run check`; benchmark command required for performance-sensitive edits |
|
|
26
|
+
| Headless environment, controller loop, worker protocol, Policy Runner, observation/vector/schema contract | Focused environment/controller/transport tests and active observation contract assertions | `npm run check`; benchmark if compact/vector/snapshot cost changes |
|
|
27
|
+
| Browser runtime, Pixi lifecycle, layout support, readouts, controls, theme, loading, or smoke pages | Focused DOM/render helper tests where possible | `npm run check`; full browser smoke for broad layout/showcase changes |
|
|
28
|
+
| Docs-only consumer guidance | `npm run docs:check` | `npm run check` when docs describe package behavior changed in code |
|
|
29
|
+
|
|
30
|
+
## Test Quality Rules
|
|
31
|
+
|
|
32
|
+
- Test behavior through the production path whenever practical. Avoid tests that recreate private helper logic and only prove the helper still matches itself.
|
|
33
|
+
- Include negative, stale-state, restart/remount, and partial-update cases for lifecycle code.
|
|
34
|
+
- For deterministic simulation changes, fix the seed, track seed, drivers, entries, rules, and scenario inputs in the test.
|
|
35
|
+
- For model-facing senses, assert the active observation/vector/schema contract. Debug overlays may have extra data, but no model-sense panel should display a recomputed or more precise value as model input.
|
|
36
|
+
- For performance-sensitive paths, assert counters that explain the cost, such as fallback counts, allocation counters, or compact payload sizes. Do not rely only on elapsed time.
|
|
37
|
+
- For package boundary work, prove public imports from the packed package, not internal relative paths.
|
|
38
|
+
- For browser layout work, prove rendered behavior with browser smoke or a focused DOM/canvas check. Static markup snapshots are not enough when resize observers, canvas painting, or runtime CSS state are involved.
|
|
39
|
+
|
|
40
|
+
## High-Risk Behaviors To Map In Audits
|
|
41
|
+
|
|
42
|
+
- `mountF1Simulator()` and `createPaddockSimulator()` lifecycle: initial shell, loading overlays, start, restart, theme sync, destroy, and repeated mount behavior.
|
|
43
|
+
- Public subpath boundaries: root imports browser/CSS runtime, `/environment` stays browser-free and CSS-free, `/data` stays CSS-free, `/placeholder` stays tiny and inert.
|
|
44
|
+
- Determinism: same seed, track seed, drivers, entries, rules, and scenario produce stable simulation behavior.
|
|
45
|
+
- Track query index propagation: built runtime tracks keep the internal non-enumerable index, while public JSON snapshots do not leak engine helpers.
|
|
46
|
+
- Race state transitions: start sequence, safety car, red flag, pit-lane open/closed, pit stops, penalties, DNF, finish, and final classification.
|
|
47
|
+
- Model-facing observations: object/vector/schema alignment, per-driver overrides, compact/vector-only outputs, reset-only observations, and external renderer frames.
|
|
48
|
+
- Rendering and layout: nonblank canvas, timing tower constraints, unsupported-size placeholders, lower-third/timing clearance, theme variables, and composable roots.
|
|
49
|
+
- Package consumption: dry pack contents, fresh consumer install/build, browser showcase build, and documented host update path.
|
|
50
|
+
|
|
51
|
+
## Reporting Standard
|
|
52
|
+
|
|
53
|
+
Every reliability audit should report:
|
|
54
|
+
|
|
55
|
+
- current confidence: what is proven and what remains unproven;
|
|
56
|
+
- findings ranked by user impact and regression likelihood;
|
|
57
|
+
- exact files and behavior paths affected;
|
|
58
|
+
- smallest test or verification change that would close each gap;
|
|
59
|
+
- commands run, with the gate level they prove;
|
|
60
|
+
- any rejected critique, with the technical reason it is not accepted.
|
|
61
|
+
|
|
62
|
+
If a required command is blocked by the environment, report the command, failure text, retry state, and the exact proof still missing. Do not replace a broad required gate with a narrow check.
|