@inventure71/paddockjs 0.1.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/AGENTS.md +86 -0
- package/CHANGELOG.md +5 -0
- package/LICENSE +176 -0
- package/README.md +165 -0
- package/assets/f1-broadcast-panel-surface.png +0 -0
- package/assets/f1-car-sprite-game.png +0 -0
- package/assets/f1-driver-helmet.png +0 -0
- package/assets/f1-safety-car-sprite.png +0 -0
- package/assets/f1-texture-asphalt.png +0 -0
- package/assets/f1Logo.png +0 -0
- package/docs/architecture.md +209 -0
- package/docs/concepts.md +178 -0
- package/docs/data_contract.md +360 -0
- package/docs/data_model.md +167 -0
- package/docs/index.md +15 -0
- package/docs/learnings.md +47 -0
- package/docs/rules.md +181 -0
- package/docs/system_specs.md +211 -0
- package/package.json +85 -0
- package/src/api/PaddockSimulatorController.js +233 -0
- package/src/app/F1SimulatorApp.js +1293 -0
- package/src/app/domBindings.js +64 -0
- package/src/config/defaultAssets.js +29 -0
- package/src/config/defaultOptions.js +184 -0
- package/src/data/championship.js +225 -0
- package/src/data/customFields.js +14 -0
- package/src/data/demoDrivers.js +134 -0
- package/src/data/driverData.js +71 -0
- package/src/data/normalizeDrivers.js +21 -0
- package/src/data/vehicleData.js +81 -0
- package/src/index.d.ts +399 -0
- package/src/index.js +116 -0
- package/src/rendering/proceduralTrackAsset.js +517 -0
- package/src/rendering/renderSnapshot.js +23 -0
- package/src/simulation/driverController.js +253 -0
- package/src/simulation/raceSimulation.js +933 -0
- package/src/simulation/simMath.js +34 -0
- package/src/simulation/trackModel.js +607 -0
- package/src/simulation/units.js +30 -0
- package/src/simulation/vehiclePhysics.js +104 -0
- package/src/standalone.js +15 -0
- package/src/styles.css +1818 -0
- package/src/ui/componentTemplates.js +229 -0
- package/src/ui/shellTemplate.js +43 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Project
|
|
4
|
+
|
|
5
|
+
PaddockJS is an installable browser component package for an F1-style project race simulator.
|
|
6
|
+
|
|
7
|
+
The package lives independently from the portfolio website. Host websites install it and mount it with:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
import { mountF1Simulator } from '@inventure71/paddockjs';
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
It can also be mounted as rearrangeable package-owned pieces with:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import { createPaddockSimulator } from '@inventure71/paddockjs';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## What Is In This Repo
|
|
20
|
+
|
|
21
|
+
- `src/index.js`: public package API.
|
|
22
|
+
- `src/api/`: public composable mounting controller.
|
|
23
|
+
- `src/app/`: browser runtime, DOM bindings, PixiJS app lifecycle, controls, readouts, and camera orchestration.
|
|
24
|
+
- `src/config/`: default options and bundled default asset mapping.
|
|
25
|
+
- `src/data/`: driver/project data normalization, driver/car pairing, rating conversion, and demo data.
|
|
26
|
+
- `src/rendering/`: PixiJS track rendering helpers and render interpolation.
|
|
27
|
+
- `src/simulation/`: race rules, driver AI, vehicle physics, track model, and math utilities.
|
|
28
|
+
- `src/ui/`: generated markup for the all-in-one shell and individually mounted UI surfaces.
|
|
29
|
+
- `src/__tests__/`: package tests.
|
|
30
|
+
- `assets/`: simulator-owned default assets.
|
|
31
|
+
- `docs/`: package specs and design documentation.
|
|
32
|
+
- `INSTALL_AND_UPDATE.md`: install/update workflow.
|
|
33
|
+
|
|
34
|
+
## Required Documentation Discipline
|
|
35
|
+
|
|
36
|
+
When changing simulator behavior, update docs in the same change.
|
|
37
|
+
|
|
38
|
+
Use this mapping:
|
|
39
|
+
|
|
40
|
+
- Public API, lifecycle, install assumptions: update `docs/system_specs.md` and `README.md` if needed.
|
|
41
|
+
- Race behavior, DRS, safety car, starts, physics, collisions: update `docs/rules.md`.
|
|
42
|
+
- Vocabulary or domain model: update `docs/concepts.md`.
|
|
43
|
+
- Driver/entry/options/assets callback shapes: update `docs/data_contract.md`.
|
|
44
|
+
- Module ownership or data/control flow: update `docs/architecture.md`.
|
|
45
|
+
- Local install/update workflow: update `INSTALL_AND_UPDATE.md`.
|
|
46
|
+
|
|
47
|
+
Do not leave docs describing old behavior after code changes.
|
|
48
|
+
|
|
49
|
+
## Linear Work Logging
|
|
50
|
+
|
|
51
|
+
For any implementation that is more than a trivial/no-op change, log the work in the PaddockJS project on Linear.
|
|
52
|
+
|
|
53
|
+
The Linear update must include:
|
|
54
|
+
|
|
55
|
+
- what task was done
|
|
56
|
+
- how it was solved
|
|
57
|
+
- any important verification or remaining follow-up
|
|
58
|
+
|
|
59
|
+
## Engineering Rules
|
|
60
|
+
|
|
61
|
+
- Preserve the package boundary: PaddockJS should stay reusable and host-agnostic.
|
|
62
|
+
- Host-specific routing belongs in `onDriverOpen(driver)`, not package internals.
|
|
63
|
+
- Host-specific project data should be passed as `drivers` and `entries`, not hardcoded into the runtime.
|
|
64
|
+
- The package should own default simulator assets so hosts do not need to copy them.
|
|
65
|
+
- Treat the timing board width and broadcast proportions as package-owned. Do not resize or retune timing-board width as a casual fix; preserve its intended width and solve layout bugs through internal column/content constraints unless the user explicitly asks to redesign the timing board sizing.
|
|
66
|
+
- Prefer small, focused modules when extracting from `F1SimulatorApp.js`.
|
|
67
|
+
- Keep simulation logic deterministic for the same seed, track seed, drivers, entries, and rules.
|
|
68
|
+
- Do not claim completion without running verification.
|
|
69
|
+
|
|
70
|
+
## Verification
|
|
71
|
+
|
|
72
|
+
Run before claiming package changes are complete:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npm run check
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
For portfolio integration changes, also run from the portfolio repo:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
cd /Users/inventure71/VSProjects/Inventure71.github.io
|
|
82
|
+
npm install ../PaddockJS
|
|
83
|
+
npm run check
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Browser behavior changes need a browser smoke test against the host page.
|
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
package/README.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# PaddockJS
|
|
2
|
+
|
|
3
|
+
This folder is the extractable F1 simulator component. It owns the simulator source, bundled simulator assets, CSS, demo data, and the public mount API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
From npm:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @inventure71/paddockjs
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For local sibling-repo development:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install ../PaddockJS
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Documentation
|
|
20
|
+
|
|
21
|
+
Start with [docs/index.md](docs/index.md) for system specs, rules, concepts, data contracts, and architecture notes.
|
|
22
|
+
|
|
23
|
+
## Package Workflow
|
|
24
|
+
|
|
25
|
+
The repo now includes the full package-release boundary:
|
|
26
|
+
|
|
27
|
+
- a tracked showcase host in `local-preview/`
|
|
28
|
+
- public TypeScript declarations in `src/index.d.ts`
|
|
29
|
+
- GitHub Actions CI in `.github/workflows/ci.yml`
|
|
30
|
+
- Changesets release automation in `.github/workflows/release.yml`
|
|
31
|
+
|
|
32
|
+
Useful commands:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm run check
|
|
36
|
+
npm run showcase:dev
|
|
37
|
+
npm run showcase:build
|
|
38
|
+
npm run changeset
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`npm run check` verifies the runtime tests, public declaration file, dry package contents, and showcase build.
|
|
42
|
+
|
|
43
|
+
## API
|
|
44
|
+
|
|
45
|
+
All-in-one mount:
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
import { mountF1Simulator } from '@inventure71/paddockjs';
|
|
49
|
+
|
|
50
|
+
const simulator = await mountF1Simulator(document.getElementById('sim-root'), {
|
|
51
|
+
preset: 'timing-overlay',
|
|
52
|
+
drivers: [
|
|
53
|
+
{
|
|
54
|
+
id: 'budget',
|
|
55
|
+
name: 'Budget Buddy',
|
|
56
|
+
color: '#ff2d55',
|
|
57
|
+
link: '/project_details/project-budget-buddy.html',
|
|
58
|
+
raceData: ['AI finance coach', 'Python + LLM', 'Budget guardrails'],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
entries: [
|
|
62
|
+
{
|
|
63
|
+
driverId: 'budget',
|
|
64
|
+
driverNumber: 71,
|
|
65
|
+
timingName: 'Budget',
|
|
66
|
+
driver: { pace: 52, racecraft: 74, aggression: 38, riskTolerance: 47, patience: 81, consistency: 86 },
|
|
67
|
+
vehicle: { id: 'budget-bb01', name: 'BB-01 Ledger', power: 48, braking: 72, aero: 55, dragEfficiency: 66, mechanicalGrip: 63, weightControl: 58, tireCare: 82 },
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
onDriverOpen(driver) {
|
|
71
|
+
window.location.href = driver.link;
|
|
72
|
+
},
|
|
73
|
+
onRaceFinish({ winner, classification }) {
|
|
74
|
+
console.log('Race winner:', winner.name, classification);
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Composable mount:
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
import { createPaddockSimulator } from '@inventure71/paddockjs';
|
|
83
|
+
|
|
84
|
+
const simulator = createPaddockSimulator({
|
|
85
|
+
drivers,
|
|
86
|
+
entries,
|
|
87
|
+
onDriverOpen(driver) {
|
|
88
|
+
window.location.href = driver.link;
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
simulator.mountRaceControls(document.getElementById('sim-controls'));
|
|
93
|
+
simulator.mountCameraControls(document.getElementById('sim-camera-controls'));
|
|
94
|
+
simulator.mountSafetyCarControl(document.getElementById('sim-safety-car'));
|
|
95
|
+
simulator.mountTimingTower(document.getElementById('sim-timing'));
|
|
96
|
+
simulator.mountRaceCanvas(document.getElementById('sim-race'), {
|
|
97
|
+
includeRaceDataPanel: true,
|
|
98
|
+
});
|
|
99
|
+
simulator.mountTelemetryPanel(document.getElementById('sim-telemetry'));
|
|
100
|
+
simulator.mountCarDriverOverview(document.getElementById('sim-overview'));
|
|
101
|
+
|
|
102
|
+
await simulator.start();
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The race canvas can also own the timing tower when a host wants a single reusable race-window component:
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
simulator.mountRaceCanvas(document.getElementById('sim-race'), {
|
|
109
|
+
includeTimingTower: true,
|
|
110
|
+
includeRaceDataPanel: true,
|
|
111
|
+
timingTowerVerticalFit: 'scroll',
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`drivers` is the host-owned project/pilot list. `entries` is the optional driver/car/team pairing sheet. The car/driver overview uses the existing driver and vehicle rating components from each entry. Driver and vehicle entries can also include `customFields` as extra label/value metadata. Entries can include `team: { id, name, color, icon }`; the timing tower uses the team icon and defaults team color to the car color when omitted. Assets, including the default car image and generic driver helmet, are bundled by default, so the host website does not need to provide simulator images or textures.
|
|
116
|
+
|
|
117
|
+
The returned object supports:
|
|
118
|
+
|
|
119
|
+
- `destroy()`
|
|
120
|
+
- `restart(nextOptions)`
|
|
121
|
+
- `selectDriver(driverId)`
|
|
122
|
+
- `setSafetyCarDeployed(deployed)`
|
|
123
|
+
- `callSafetyCar()`
|
|
124
|
+
- `clearSafetyCar()`
|
|
125
|
+
- `toggleSafetyCar()`
|
|
126
|
+
- `getSnapshot()`
|
|
127
|
+
|
|
128
|
+
Useful UI options:
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
preset: 'timing-overlay',
|
|
132
|
+
theme: {
|
|
133
|
+
accentColor: '#00ff84',
|
|
134
|
+
timingTowerMaxWidth: '360px',
|
|
135
|
+
raceViewMinHeight: '720px',
|
|
136
|
+
},
|
|
137
|
+
ui: {
|
|
138
|
+
layoutPreset: 'left-tower-overlay',
|
|
139
|
+
cameraControls: 'external',
|
|
140
|
+
showFps: false,
|
|
141
|
+
telemetryIncludesOverview: false,
|
|
142
|
+
raceDataBanners: {
|
|
143
|
+
initial: 'project',
|
|
144
|
+
enabled: ['project', 'radio'],
|
|
145
|
+
},
|
|
146
|
+
raceDataBannerSize: 'auto',
|
|
147
|
+
timingTowerVerticalFit: 'expand-race-view',
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`preset` is resolved before explicit host options. Available presets are `dashboard`, `timing-overlay`, `compact-race`, and `full-dashboard`; hosts can start from a preset and override any `ui` or `theme` field. `theme` maps to package CSS variables for the stable sizing/color contract: `accentColor`, `greenColor`, `yellowColor`, `timingTowerMaxWidth`, and `raceViewMinHeight`.
|
|
152
|
+
|
|
153
|
+
If `trackSeed` is omitted, each mounted browser simulator creates a fresh procedural circuit. Passing `trackSeed` makes the track deterministic so multiple embeds can share the same generated circuit; repeated procedural seeds are cached within the page runtime.
|
|
154
|
+
|
|
155
|
+
`layoutPreset: 'left-tower-overlay'` creates a left broadcast gutter inside the race view, frames the camera around the remaining race area, and places the timing tower in that gutter without covering camera controls. The project/radio lower-third stays inside the race window and can intentionally render over the timing sidebar instead of shrinking around it. Composable hosts should pass `{ includeRaceDataPanel: true }` to `mountRaceCanvas()` when they want that lower-third clipped and layered by the race window; `mountRaceDataPanel()` remains available for hosts that intentionally want the banner as a standalone surface. `includeTimingTower: true` embeds the timing tower directly inside the race canvas and reserves camera space from the measured tower gutter. `raceDataBanners.initial` selects the starting banner state (`'project'`, `'radio'`, or `'hidden'`), while `raceDataBanners.enabled` chooses which banner types may appear. `raceDataBannerSize: 'auto'` uses the race space to the right of the timing board when it is wide enough and falls back to the full lower-third overlap when it is not; `'custom'` preserves the default CSS-variable-driven lower-third size for hosts that want to tune their own banner geometry. `timingTowerVerticalFit: 'expand-race-view'` lets the race window grow tall enough for the tower; `'scroll'` keeps the race window height and scrolls the timing list inside the cropped tower. The same fit values can be passed to `mountRaceCanvas()` when `includeTimingTower` is enabled. Standalone timing towers are capped by `--timing-board-max-width` and fill their mount root height; placing the root in a fixed-height container makes only the timing entries scroll. Timing entries always stack from the top as fixed rows, so P1/P2 occupy the same vertical positions whether the race has 2 cars or 20. The timing tower includes an `Int`/`Gap` broadcast switch: `Int` shows the interval to the car ahead, while `Gap` shows total gap to the leader. `cameraControls: 'external'` moves view controls out of the canvas so hosts can mount them with `mountCameraControls()`. `showFps: false` hides the FPS readout. `telemetryIncludesOverview: false` keeps telemetry text-only so hosts can mount `mountCarDriverOverview()` separately.
|
|
156
|
+
|
|
157
|
+
Mounted package surfaces include a lightweight red start-light loading overlay. The runtime removes each overlay after PixiJS, assets, controls, and the initial readouts are ready.
|
|
158
|
+
|
|
159
|
+
The runtime also pauses its render ticker when the race canvas is offscreen or the browser tab is hidden. This keeps pages with multiple PaddockJS embeds responsive without requiring host code to manually start and stop each simulator.
|
|
160
|
+
|
|
161
|
+
Lifecycle callbacks are optional and host-owned. PaddockJS emits `onLoadingChange`, `onReady`, `onError`, `onDriverSelect`, `onRaceEvent`, `onLapChange`, and `onRaceFinish`; callback errors are routed to `onError` when provided and do not stop the simulator loop. Race snapshots include per-car interval timing, leader-gap timing, calibrated `speedKph`, finish state, `raceControl.winner` after the first finisher, and final `raceControl.classification` only after the whole field finishes. The field then circulates in safety-car mode and the race canvas shows a package-owned winner banner.
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
PaddockJS is released under `Apache-2.0`. See [LICENSE](LICENSE).
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Package Boundary
|
|
4
|
+
|
|
5
|
+
PaddockJS is the simulator package. A host website imports it and passes data.
|
|
6
|
+
|
|
7
|
+
The package owns:
|
|
8
|
+
|
|
9
|
+
- Simulator source.
|
|
10
|
+
- Bundled assets.
|
|
11
|
+
- CSS.
|
|
12
|
+
- DOM shell generation.
|
|
13
|
+
- PixiJS renderer.
|
|
14
|
+
- Simulation rules and physics.
|
|
15
|
+
- Demo data.
|
|
16
|
+
- Tests.
|
|
17
|
+
|
|
18
|
+
The host owns:
|
|
19
|
+
|
|
20
|
+
- Project-specific driver data.
|
|
21
|
+
- Navigation behavior.
|
|
22
|
+
- Page placement.
|
|
23
|
+
- Host build and deployment.
|
|
24
|
+
|
|
25
|
+
## Main Flow
|
|
26
|
+
|
|
27
|
+
All-in-one flow:
|
|
28
|
+
|
|
29
|
+
```txt
|
|
30
|
+
host page
|
|
31
|
+
-> mountF1Simulator(root, options)
|
|
32
|
+
-> resolveF1SimulatorOptions(options)
|
|
33
|
+
-> normalizeSimulatorDrivers(drivers, entries)
|
|
34
|
+
-> createF1SimulatorShell(options)
|
|
35
|
+
-> new F1SimulatorApp(shell, resolvedOptions)
|
|
36
|
+
-> createRaceSimulation(...)
|
|
37
|
+
-> PixiJS render loop + DOM readout updates
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Composable flow:
|
|
41
|
+
|
|
42
|
+
```txt
|
|
43
|
+
host page
|
|
44
|
+
-> createPaddockSimulator(options)
|
|
45
|
+
-> resolveF1SimulatorOptions(options)
|
|
46
|
+
-> simulator.mountRaceControls(controlsRoot)
|
|
47
|
+
-> simulator.mountCameraControls(cameraControlsRoot)
|
|
48
|
+
-> simulator.mountSafetyCarControl(safetyCarRoot)
|
|
49
|
+
-> simulator.mountTimingTower(timingRoot)
|
|
50
|
+
-> simulator.mountRaceCanvas(canvasRoot, { includeRaceDataPanel })
|
|
51
|
+
-> simulator.mountTelemetryPanel(telemetryRoot)
|
|
52
|
+
-> simulator.mountRaceDataPanel(raceDataRoot) [optional standalone alternative]
|
|
53
|
+
-> simulator.start()
|
|
54
|
+
-> new F1SimulatorApp(compositeRoot, resolvedOptions)
|
|
55
|
+
-> PixiJS render loop + DOM readout updates
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Public Entry
|
|
59
|
+
|
|
60
|
+
`src/index.js` is the public package entry.
|
|
61
|
+
|
|
62
|
+
Responsibilities:
|
|
63
|
+
|
|
64
|
+
- Import CSS.
|
|
65
|
+
- Export package API and data helpers.
|
|
66
|
+
- Validate the root element.
|
|
67
|
+
- Resolve options.
|
|
68
|
+
- Create the DOM shell.
|
|
69
|
+
- Construct and initialize `F1SimulatorApp`.
|
|
70
|
+
- Return the controller methods.
|
|
71
|
+
- Re-export the composable mount API.
|
|
72
|
+
|
|
73
|
+
`src/api/PaddockSimulatorController.js` owns composable mounting.
|
|
74
|
+
|
|
75
|
+
Responsibilities:
|
|
76
|
+
|
|
77
|
+
- Resolve host options once for component templates and runtime.
|
|
78
|
+
- Render each independently mounted component into its host root.
|
|
79
|
+
- Build a composite DOM query surface for `F1SimulatorApp`.
|
|
80
|
+
- Initialize and control the shared simulator runtime through `start()`, `restart()`, `destroy()`, and state methods.
|
|
81
|
+
- Expose explicit safety-car methods for callers that want to deploy or release the safety car without using package-rendered buttons.
|
|
82
|
+
|
|
83
|
+
## Runtime App
|
|
84
|
+
|
|
85
|
+
`src/app/F1SimulatorApp.js` owns browser runtime behavior.
|
|
86
|
+
|
|
87
|
+
Responsibilities:
|
|
88
|
+
|
|
89
|
+
- PixiJS application setup.
|
|
90
|
+
- Asset loading.
|
|
91
|
+
- Sprite creation.
|
|
92
|
+
- Control event binding.
|
|
93
|
+
- Fixed-step simulation pacing.
|
|
94
|
+
- Viewport/document visibility throttling for the PixiJS ticker.
|
|
95
|
+
- Camera modes.
|
|
96
|
+
- Overlay-safe camera framing for the left timing-tower preset.
|
|
97
|
+
- Timing tower rendering.
|
|
98
|
+
- Telemetry rendering.
|
|
99
|
+
- Race data panel rendering.
|
|
100
|
+
- Safety car button.
|
|
101
|
+
- Multiple package-rendered safety-car buttons bound to one simulation state.
|
|
102
|
+
- Restart behavior.
|
|
103
|
+
- Lifecycle cleanup.
|
|
104
|
+
|
|
105
|
+
This file is still large. When changing it substantially, prefer extracting cohesive modules rather than adding unrelated responsibilities.
|
|
106
|
+
|
|
107
|
+
`src/app/domBindings.js` owns DOM selector lookup and null-safe readout text writes for package-generated UI surfaces.
|
|
108
|
+
|
|
109
|
+
## Simulation Core
|
|
110
|
+
|
|
111
|
+
`src/simulation/raceSimulation.js` owns race state and rules.
|
|
112
|
+
|
|
113
|
+
Responsibilities:
|
|
114
|
+
|
|
115
|
+
- Race-control mode.
|
|
116
|
+
- Start sequence.
|
|
117
|
+
- Safety car.
|
|
118
|
+
- Car creation.
|
|
119
|
+
- Race ordering.
|
|
120
|
+
- Lap calculation.
|
|
121
|
+
- Timing history.
|
|
122
|
+
- DRS eligibility.
|
|
123
|
+
- Collision response.
|
|
124
|
+
- Snapshot creation.
|
|
125
|
+
|
|
126
|
+
`src/simulation/driverController.js` owns AI control decisions.
|
|
127
|
+
|
|
128
|
+
`src/simulation/vehiclePhysics.js` owns vehicle integration and surface physics.
|
|
129
|
+
|
|
130
|
+
`src/simulation/trackModel.js` owns track construction, procedural track generation, DRS zones, and nearest-track queries. Browser mounts generate a fresh procedural seed when `trackSeed` is omitted; explicit procedural track seeds are cached so repeated mounts with the same seed do not regenerate or rebuild the same model.
|
|
131
|
+
|
|
132
|
+
`src/simulation/units.js` owns conversion between simulator units and public meter/km/h display values. Physics stays in simulator units; snapshots expose calibrated display fields such as `speedKph`, `distanceMeters`, and `gapMeters`.
|
|
133
|
+
|
|
134
|
+
`src/rendering/renderSnapshot.js` owns interpolation for rendering.
|
|
135
|
+
|
|
136
|
+
The app runtime pauses its PixiJS ticker when the race canvas is outside the viewport or the document is hidden, then resets the frame clock before resuming. This prevents host pages with several simulator embeds from running every race while only one is visible, and avoids a large simulation catch-up step when the canvas re-enters view. Camera safe-area layout measurements are cached and invalidated by resize observation so the 60 FPS render path does not force repeated DOM geometry reads. Long project-radio delays are also treated as stale schedule state instead of replaying every missed lower-third transition.
|
|
137
|
+
|
|
138
|
+
## Data Layer
|
|
139
|
+
|
|
140
|
+
`src/data/driverData.js` converts driver rating sheets into constructor arguments.
|
|
141
|
+
|
|
142
|
+
`src/data/vehicleData.js` converts vehicle rating sheets into physical setup values.
|
|
143
|
+
|
|
144
|
+
`src/data/championship.js` pairs drivers with entries and generates timing codes, numbers, team metadata, and converted constructor data.
|
|
145
|
+
|
|
146
|
+
`src/data/normalizeDrivers.js` validates host driver data and invokes championship pairing.
|
|
147
|
+
|
|
148
|
+
`src/data/demoDrivers.js` is demo/portfolio-flavored sample data. It should not become the only supported data path.
|
|
149
|
+
|
|
150
|
+
## UI Shell
|
|
151
|
+
|
|
152
|
+
`src/ui/componentTemplates.js` owns the generated markup for individual UI surfaces:
|
|
153
|
+
|
|
154
|
+
- Race controls.
|
|
155
|
+
- Camera controls.
|
|
156
|
+
- Safety-car control.
|
|
157
|
+
- Timing tower.
|
|
158
|
+
- Race canvas.
|
|
159
|
+
- Race-data panel.
|
|
160
|
+
- Telemetry panel.
|
|
161
|
+
- Car/driver overview panel.
|
|
162
|
+
|
|
163
|
+
`src/ui/shellTemplate.js` composes those component templates into the default all-in-one simulator DOM and package-owned layout presets such as `left-tower-overlay`. The telemetry panel can embed the car/driver overview, but the overview is also a separately mountable package-owned component. The left-tower overlay preset is responsible for internal component placement and package-owned proportions; the project/radio lower-third remains owned by the race canvas so it can either use the race space beside the timing tower in `auto` sizing mode or overlap the tower when space is constrained. Composable hosts can also ask the race-canvas template to embed the timing tower directly with `includeTimingTower`, using the same expand-vs-scroll vertical fit contract. `F1SimulatorApp` measures the resulting timing-tower gutter when framing the PixiJS camera, whether the tower comes from the prebuilt shell or from an embedded composable race canvas. Hosts should not provide the internal simulator markup or tune preset internals with raw sizing options.
|
|
164
|
+
|
|
165
|
+
`src/config/defaultOptions.js` owns preset resolution and the public theme contract. Presets are merged before host options; theme fields are applied as package CSS variables by the all-in-one app and composable controller. This keeps sizing/color customization explicit without turning internal layout ratios into public API.
|
|
166
|
+
|
|
167
|
+
Race completion is owned by `src/simulation/raceSimulation.js`. The app layer reads `raceControl.finished`, `winner`, and `classification` from snapshots, renders the winner banner, and emits lifecycle callbacks. UI code must not infer finish state from lap text or timing rows.
|
|
168
|
+
|
|
169
|
+
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.
|
|
170
|
+
|
|
171
|
+
`src/styles.css` styles the generated shell, imports package fonts, caps timing-tower width for readability, and owns the fixed-height timing-list scroll behavior. Timing rows are fixed grid rows stacked from the top, 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 timing values from the race snapshot. Component templates include lightweight package-owned loading overlays; `F1SimulatorApp` removes them after startup initialization has completed.
|
|
172
|
+
|
|
173
|
+
The host page should only provide:
|
|
174
|
+
|
|
175
|
+
```html
|
|
176
|
+
<div id="f1-simulator-root"></div>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Assets
|
|
180
|
+
|
|
181
|
+
`src/config/defaultAssets.js` imports bundled assets from `assets/` and exposes default asset resolution.
|
|
182
|
+
|
|
183
|
+
Assets are bundled by the host build tool when the package is imported.
|
|
184
|
+
|
|
185
|
+
## Tests
|
|
186
|
+
|
|
187
|
+
Tests live in `src/__tests__/`.
|
|
188
|
+
|
|
189
|
+
Current coverage includes:
|
|
190
|
+
|
|
191
|
+
- Championship metadata.
|
|
192
|
+
- Component API and callback behavior.
|
|
193
|
+
- Driver controller behavior.
|
|
194
|
+
- Procedural track rendering helpers.
|
|
195
|
+
- Race simulation rules.
|
|
196
|
+
- Render interpolation.
|
|
197
|
+
- Track model behavior.
|
|
198
|
+
|
|
199
|
+
Run:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
npm test
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Design Rule
|
|
206
|
+
|
|
207
|
+
Keep reusable simulator behavior in PaddockJS. Keep website-specific data and routing in the host.
|
|
208
|
+
|
|
209
|
+
If a change adds portfolio-only behavior to package internals, move it to the host integration layer instead.
|