@inventure71/paddockjs 0.1.0 → 0.3.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/INSTALL_AND_UPDATE.md +163 -0
  3. package/README.md +96 -16
  4. package/docs/architecture.md +55 -11
  5. package/docs/concepts.md +5 -1
  6. package/docs/data_contract.md +324 -8
  7. package/docs/data_model.md +1 -0
  8. package/docs/index.md +1 -0
  9. package/docs/rules.md +2 -0
  10. package/docs/system_specs.md +66 -11
  11. package/docs/training.md +104 -0
  12. package/examples/train-basic-policy.mjs +277 -0
  13. package/package.json +14 -7
  14. package/src/api/PaddockSimulatorController.js +64 -3
  15. package/src/app/BrowserExpertAdapter.js +32 -0
  16. package/src/app/F1SimulatorApp.js +308 -38
  17. package/src/app/domBindings.js +35 -11
  18. package/src/config/defaultOptions.js +33 -0
  19. package/src/data/championship.js +13 -0
  20. package/src/data/normalizeDrivers.js +7 -2
  21. package/src/environment/actions.js +45 -0
  22. package/src/environment/episode.js +17 -0
  23. package/src/environment/events.js +17 -0
  24. package/src/environment/index.d.ts +241 -0
  25. package/src/environment/index.js +2 -0
  26. package/src/environment/observations.js +112 -0
  27. package/src/environment/options.js +150 -0
  28. package/src/environment/rewards.js +69 -0
  29. package/src/environment/runtime.js +140 -0
  30. package/src/environment/sensors.js +257 -0
  31. package/src/environment/specs.js +79 -0
  32. package/src/index.d.ts +97 -4
  33. package/src/index.js +12 -2
  34. package/src/rendering/proceduralTrackAsset.js +7 -1
  35. package/src/simulation/raceSimulation.js +214 -1
  36. package/src/simulation/trackModel.js +21 -0
  37. package/src/styles.css +495 -2
  38. package/src/ui/componentTemplates.js +201 -4
  39. package/AGENTS.md +0 -86
  40. package/src/standalone.js +0 -15
package/src/styles.css CHANGED
@@ -294,6 +294,20 @@
294
294
  overflow: hidden;
295
295
  }
296
296
 
297
+ .telemetry-stack {
298
+ display: grid;
299
+ gap: 0.72rem;
300
+ min-height: 0;
301
+ }
302
+
303
+ .telemetry-stack > .sim-telemetry {
304
+ min-height: auto;
305
+ }
306
+
307
+ .telemetry-component {
308
+ width: 100%;
309
+ }
310
+
297
311
  .sim-timing.broadcast-tower {
298
312
  position: relative;
299
313
  width: min(100%, var(--timing-board-max-width));
@@ -722,6 +736,109 @@
722
736
  display: block;
723
737
  }
724
738
 
739
+ .race-telemetry-drawer {
740
+ --telemetry-drawer-width: min(390px, max(300px, 30cqw));
741
+ position: relative;
742
+ display: block;
743
+ container-type: inline-size;
744
+ inline-size: 100%;
745
+ min-height: var(--paddock-race-view-min-height, 620px);
746
+ overflow: hidden;
747
+ background: #000;
748
+ }
749
+
750
+ .race-telemetry-drawer__race {
751
+ min-width: 0;
752
+ display: flex;
753
+ min-height: inherit;
754
+ margin-right: 0;
755
+ transition: margin-right 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
756
+ }
757
+
758
+ .race-telemetry-drawer.is-telemetry-open .race-telemetry-drawer__race {
759
+ margin-right: var(--telemetry-drawer-width);
760
+ }
761
+
762
+ .race-telemetry-drawer__race > .sim-canvas-panel {
763
+ flex: 1 1 auto;
764
+ min-height: inherit;
765
+ height: auto;
766
+ }
767
+
768
+ .race-telemetry-drawer__controls {
769
+ position: absolute;
770
+ z-index: 12;
771
+ top: 1rem;
772
+ right: 1rem;
773
+ display: flex;
774
+ flex-wrap: wrap;
775
+ justify-content: flex-end;
776
+ gap: 0.45rem;
777
+ }
778
+
779
+ .race-telemetry-drawer__controls .sim-control,
780
+ .race-telemetry-drawer__controls .telemetry-drawer-toggle {
781
+ min-height: 2.45rem;
782
+ padding: 0.62rem 0.72rem;
783
+ box-shadow: 0 14px 34px rgba(0, 0, 0, 0.3);
784
+ }
785
+
786
+ .telemetry-drawer-toggle {
787
+ border: 1px solid rgba(255, 255, 255, 0.26);
788
+ color: #08090b;
789
+ background: var(--green);
790
+ font-family: var(--font-mono);
791
+ font-size: 0.66rem;
792
+ font-weight: 900;
793
+ letter-spacing: 0.12em;
794
+ text-transform: uppercase;
795
+ cursor: pointer;
796
+ }
797
+
798
+ .telemetry-drawer {
799
+ position: absolute;
800
+ z-index: 11;
801
+ top: 0;
802
+ right: 0;
803
+ bottom: 0;
804
+ width: var(--telemetry-drawer-width);
805
+ min-width: 0;
806
+ height: 100%;
807
+ overflow: hidden;
808
+ color: var(--text);
809
+ background:
810
+ linear-gradient(180deg, rgba(255, 255, 255, 0.075), transparent 22%),
811
+ rgba(8, 9, 11, 0.97);
812
+ border-left: 1px solid var(--line);
813
+ transform: translate3d(100%, 0, 0);
814
+ opacity: 0;
815
+ pointer-events: none;
816
+ will-change: transform, opacity;
817
+ transition:
818
+ transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1),
819
+ opacity 180ms ease;
820
+ }
821
+
822
+ .race-telemetry-drawer.is-telemetry-open .telemetry-drawer {
823
+ transform: translate3d(0, 0, 0);
824
+ opacity: 1;
825
+ pointer-events: auto;
826
+ }
827
+
828
+ .telemetry-drawer__header {
829
+ min-height: 3.4rem;
830
+ border-bottom: 1px solid var(--line);
831
+ }
832
+
833
+ .telemetry-drawer__content {
834
+ display: grid;
835
+ gap: 0.72rem;
836
+ height: calc(100% - 3.4rem);
837
+ padding: 0.72rem;
838
+ overflow-y: auto;
839
+ scrollbar-width: thin;
840
+ }
841
+
725
842
  .camera-controls {
726
843
  position: absolute;
727
844
  top: 1rem;
@@ -1141,6 +1258,55 @@
1141
1258
  transform: translateX(-8px);
1142
1259
  }
1143
1260
 
1261
+ .race-data-panel--with-telemetry {
1262
+ grid-template-columns: clamp(6.5rem, 11vw, 8.7rem) minmax(220px, 1fr) minmax(190px, 0.48fr) auto;
1263
+ min-height: 112px;
1264
+ }
1265
+
1266
+ .race-data-telemetry {
1267
+ position: relative;
1268
+ z-index: 1;
1269
+ grid-column: 3;
1270
+ grid-row: 1;
1271
+ align-self: stretch;
1272
+ display: grid;
1273
+ grid-template-rows: auto minmax(0, 1fr);
1274
+ gap: 0.4rem;
1275
+ min-width: 0;
1276
+ padding: 0.85rem 0.65rem;
1277
+ border-left: 1px solid rgba(255, 255, 255, 0.13);
1278
+ }
1279
+
1280
+ .race-data-telemetry__label {
1281
+ color: var(--driver-color, var(--red));
1282
+ font-family: var(--font-mono);
1283
+ font-size: 0.58rem;
1284
+ font-weight: 900;
1285
+ letter-spacing: 0.14em;
1286
+ line-height: 1;
1287
+ text-transform: uppercase;
1288
+ }
1289
+
1290
+ .race-data-telemetry__bars {
1291
+ display: grid;
1292
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1293
+ gap: 0.28rem;
1294
+ min-width: 0;
1295
+ }
1296
+
1297
+ .race-data-sector-bar {
1298
+ min-height: 3.85rem;
1299
+ padding: 0.52rem 0.42rem;
1300
+ }
1301
+
1302
+ .race-data-panel--with-telemetry .race-data-link {
1303
+ grid-column: 4;
1304
+ }
1305
+
1306
+ .race-data-panel.is-radio-mode .race-data-telemetry {
1307
+ display: none;
1308
+ }
1309
+
1144
1310
  .race-data-panel.is-radio-mode {
1145
1311
  grid-template-columns: minmax(280px, 1fr);
1146
1312
  }
@@ -1263,6 +1429,239 @@
1263
1429
  text-align: right;
1264
1430
  }
1265
1431
 
1432
+ .telemetry-module-header {
1433
+ display: flex;
1434
+ align-items: baseline;
1435
+ justify-content: space-between;
1436
+ gap: 0.75rem;
1437
+ margin-bottom: 0.65rem;
1438
+ text-transform: uppercase;
1439
+ }
1440
+
1441
+ .telemetry-module-header span {
1442
+ color: var(--muted);
1443
+ font-family: var(--font-mono);
1444
+ font-size: 0.66rem;
1445
+ font-weight: 800;
1446
+ letter-spacing: 0.14em;
1447
+ }
1448
+
1449
+ .telemetry-module-header strong {
1450
+ color: var(--green);
1451
+ font-family: var(--font-mono);
1452
+ font-size: 0.7rem;
1453
+ font-weight: 900;
1454
+ letter-spacing: 0.08em;
1455
+ }
1456
+
1457
+ .telemetry-sector-bars {
1458
+ display: grid;
1459
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1460
+ gap: 0.35rem;
1461
+ }
1462
+
1463
+ .telemetry-sector-bar {
1464
+ --sector-status-color: var(--green);
1465
+ --sector-status-bg: color-mix(in srgb, var(--sector-status-color) 10%, rgba(8, 10, 14, 0.94));
1466
+ position: relative;
1467
+ isolation: isolate;
1468
+ min-width: 0;
1469
+ overflow: hidden;
1470
+ padding: 0.55rem 0.46rem 0.48rem;
1471
+ color: rgba(244, 247, 251, 0.84);
1472
+ background:
1473
+ linear-gradient(90deg, color-mix(in srgb, var(--sector-status-color) 72%, transparent) var(--sector-fill, 0%), rgba(255, 255, 255, 0.055) 0),
1474
+ var(--sector-status-bg);
1475
+ border: 1px solid rgba(255, 255, 255, 0.12);
1476
+ box-shadow: inset 0 -2px 0 rgba(255, 255, 255, 0.05);
1477
+ }
1478
+
1479
+ .telemetry-sector-bar.is-active {
1480
+ border-color: color-mix(in srgb, var(--green) 65%, rgba(255, 255, 255, 0.22));
1481
+ box-shadow:
1482
+ inset 0 -2px 0 var(--green),
1483
+ 0 0 24px rgba(20, 199, 132, 0.12);
1484
+ }
1485
+
1486
+ .telemetry-sector-bar.is-complete {
1487
+ color: #08090b;
1488
+ }
1489
+
1490
+ .telemetry-sector-bar.is-overall-best,
1491
+ .telemetry-sector-table td.is-overall-best {
1492
+ --sector-status-color: #c77dff;
1493
+ --sector-status-bg: color-mix(in srgb, #c77dff 23%, rgba(8, 10, 14, 0.94));
1494
+ color: #fff;
1495
+ }
1496
+
1497
+ .telemetry-sector-bar.is-personal-best,
1498
+ .telemetry-sector-table td.is-personal-best {
1499
+ --sector-status-color: var(--green);
1500
+ --sector-status-bg: color-mix(in srgb, var(--green) 20%, rgba(8, 10, 14, 0.94));
1501
+ color: #ecfff7;
1502
+ }
1503
+
1504
+ .telemetry-sector-bar.is-slower,
1505
+ .telemetry-sector-table td.is-slower {
1506
+ --sector-status-color: var(--yellow);
1507
+ --sector-status-bg: color-mix(in srgb, var(--yellow) 16%, rgba(8, 10, 14, 0.94));
1508
+ color: #fff2b8;
1509
+ }
1510
+
1511
+ .telemetry-sector-table td.is-overall-best,
1512
+ .telemetry-sector-table td.is-personal-best,
1513
+ .telemetry-sector-table td.is-slower {
1514
+ background:
1515
+ linear-gradient(90deg, color-mix(in srgb, var(--sector-status-color) 28%, transparent), transparent 72%),
1516
+ var(--sector-status-bg);
1517
+ box-shadow: inset 3px 0 0 var(--sector-status-color);
1518
+ }
1519
+
1520
+ .telemetry-sector-bar span,
1521
+ .telemetry-sector-bar strong {
1522
+ position: relative;
1523
+ z-index: 1;
1524
+ display: block;
1525
+ font-family: var(--font-mono);
1526
+ line-height: 1;
1527
+ text-shadow: 0 1px 8px rgba(0, 0, 0, 0.32);
1528
+ }
1529
+
1530
+ .telemetry-sector-bar span {
1531
+ margin-bottom: 0.4rem;
1532
+ font-size: 0.58rem;
1533
+ font-weight: 900;
1534
+ letter-spacing: 0.16em;
1535
+ }
1536
+
1537
+ .telemetry-sector-bar strong {
1538
+ overflow: hidden;
1539
+ font-size: 0.72rem;
1540
+ font-weight: 900;
1541
+ text-overflow: ellipsis;
1542
+ white-space: nowrap;
1543
+ }
1544
+
1545
+ .telemetry-sector-banner {
1546
+ --sector-status-color: var(--green);
1547
+ --sector-banner-color: var(--driver-color, var(--green));
1548
+ position: absolute;
1549
+ z-index: 9;
1550
+ right: 1rem;
1551
+ bottom: 1rem;
1552
+ display: grid;
1553
+ grid-template-columns: minmax(9rem, 0.8fr) minmax(14rem, 1.2fr);
1554
+ gap: 0.65rem;
1555
+ align-items: stretch;
1556
+ width: min(560px, calc(100% - 2rem));
1557
+ padding: 0.65rem;
1558
+ color: var(--text);
1559
+ background:
1560
+ linear-gradient(110deg, rgba(8, 10, 16, 0.98), rgba(24, 29, 40, 0.92)),
1561
+ repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 58px);
1562
+ border-left: 4px solid var(--sector-banner-color);
1563
+ border-bottom: 2px solid var(--sector-banner-color);
1564
+ clip-path: polygon(0 0, calc(100% - 14px) 0, 100% 14px, 100% 100%, 14px 100%, 0 calc(100% - 14px));
1565
+ box-shadow: 0 16px 42px rgba(0, 0, 0, 0.42), inset 0 1px rgba(255, 255, 255, 0.12);
1566
+ }
1567
+
1568
+ .sim-canvas-panel:has(.race-data-panel:not(.is-hidden)) .telemetry-sector-banner {
1569
+ bottom: 8.3rem;
1570
+ }
1571
+
1572
+ .telemetry-sector-banner__copy {
1573
+ min-width: 0;
1574
+ padding: 0.28rem 0.35rem;
1575
+ text-transform: uppercase;
1576
+ }
1577
+
1578
+ .telemetry-sector-banner__copy span {
1579
+ display: block;
1580
+ color: var(--sector-banner-color);
1581
+ font-family: var(--font-mono);
1582
+ font-size: 0.62rem;
1583
+ font-weight: 900;
1584
+ letter-spacing: 0.14em;
1585
+ }
1586
+
1587
+ .telemetry-sector-banner__copy b {
1588
+ color: inherit;
1589
+ font: inherit;
1590
+ }
1591
+
1592
+ .telemetry-sector-banner__copy strong {
1593
+ display: block;
1594
+ margin-top: 0.2rem;
1595
+ overflow: hidden;
1596
+ font-size: clamp(1.15rem, 2vw, 1.65rem);
1597
+ font-weight: 900;
1598
+ line-height: 0.92;
1599
+ text-overflow: ellipsis;
1600
+ white-space: nowrap;
1601
+ }
1602
+
1603
+ .telemetry-sector-banner__copy em {
1604
+ display: block;
1605
+ margin-top: 0.28rem;
1606
+ color: rgba(244, 247, 251, 0.68);
1607
+ font-family: var(--font-mono);
1608
+ font-size: 0.66rem;
1609
+ font-style: normal;
1610
+ font-weight: 900;
1611
+ letter-spacing: 0.12em;
1612
+ }
1613
+
1614
+ .telemetry-sector-banner__bars {
1615
+ align-self: stretch;
1616
+ display: grid;
1617
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1618
+ gap: 0.32rem;
1619
+ }
1620
+
1621
+ .telemetry-lap-table,
1622
+ .telemetry-sector-table {
1623
+ width: 100%;
1624
+ border-collapse: collapse;
1625
+ overflow: hidden;
1626
+ background: rgba(255, 255, 255, 0.045);
1627
+ font-family: var(--font-mono);
1628
+ }
1629
+
1630
+ .telemetry-lap-table tr,
1631
+ .telemetry-sector-table tr {
1632
+ border-bottom: 1px solid rgba(255, 255, 255, 0.075);
1633
+ }
1634
+
1635
+ .telemetry-lap-table tr:last-child,
1636
+ .telemetry-sector-table tr:last-child {
1637
+ border-bottom: 0;
1638
+ }
1639
+
1640
+ .telemetry-lap-table th,
1641
+ .telemetry-lap-table td,
1642
+ .telemetry-sector-table th,
1643
+ .telemetry-sector-table td {
1644
+ padding: 0.55rem 0.5rem;
1645
+ font-size: 0.68rem;
1646
+ line-height: 1;
1647
+ text-align: right;
1648
+ }
1649
+
1650
+ .telemetry-lap-table th,
1651
+ .telemetry-sector-table th {
1652
+ color: var(--muted);
1653
+ font-weight: 800;
1654
+ letter-spacing: 0.09em;
1655
+ text-align: left;
1656
+ text-transform: uppercase;
1657
+ }
1658
+
1659
+ .telemetry-lap-table td,
1660
+ .telemetry-sector-table td {
1661
+ color: var(--text);
1662
+ font-weight: 900;
1663
+ }
1664
+
1266
1665
  .car-overview {
1267
1666
  position: relative;
1268
1667
  margin-top: 1rem;
@@ -1676,7 +2075,12 @@
1676
2075
 
1677
2076
  .sim-shell--left-tower-overlay .sim-timing,
1678
2077
  .sim-canvas-panel--with-timing-tower > .sim-timing {
1679
- width: min(72vw, var(--timing-board-max-width));
2078
+ width: min(100%, var(--timing-board-max-width));
2079
+ }
2080
+
2081
+ .sim-shell--left-tower-overlay .sim-timing {
2082
+ width: 100%;
2083
+ max-width: 100%;
1680
2084
  }
1681
2085
 
1682
2086
  .sim-topbar {
@@ -1703,8 +2107,33 @@
1703
2107
  min-height: 58svh;
1704
2108
  }
1705
2109
 
2110
+ .race-telemetry-drawer {
2111
+ --telemetry-drawer-width: 100%;
2112
+ }
2113
+
2114
+ .race-telemetry-drawer__race,
2115
+ .race-telemetry-drawer.is-telemetry-open .race-telemetry-drawer__race {
2116
+ margin-right: 0;
2117
+ }
2118
+
2119
+ .race-telemetry-drawer.is-telemetry-open .race-telemetry-drawer__race {
2120
+ margin-bottom: min(360px, 46svh);
2121
+ }
2122
+
2123
+ .telemetry-drawer {
2124
+ top: auto;
2125
+ height: min(360px, 46svh);
2126
+ border-left: 0;
2127
+ border-top: 1px solid var(--line);
2128
+ transform: translate3d(0, 100%, 0);
2129
+ }
2130
+
2131
+ .race-telemetry-drawer.is-telemetry-open .telemetry-drawer {
2132
+ transform: translate3d(0, 0, 0);
2133
+ }
2134
+
1706
2135
  .camera-controls {
1707
- max-width: calc(100% - 5.4rem);
2136
+ max-width: calc(100% - 1.5rem);
1708
2137
  }
1709
2138
 
1710
2139
  .race-data-panel {
@@ -1715,15 +2144,46 @@
1715
2144
  min-height: 88px;
1716
2145
  }
1717
2146
 
2147
+ .telemetry-sector-banner {
2148
+ right: 0.75rem;
2149
+ bottom: 0.75rem;
2150
+ grid-template-columns: 1fr;
2151
+ width: calc(100% - 1.5rem);
2152
+ }
2153
+
2154
+ .sim-canvas-panel:has(.race-data-panel:not(.is-hidden)) .telemetry-sector-banner {
2155
+ bottom: 8rem;
2156
+ }
2157
+
1718
2158
  .race-data-panel.is-radio-mode {
1719
2159
  grid-template-columns: minmax(0, 1fr);
1720
2160
  }
1721
2161
 
2162
+ .race-data-panel--with-telemetry {
2163
+ grid-template-columns: minmax(4.8rem, auto) minmax(0, 1fr);
2164
+ }
2165
+
1722
2166
  .race-data-copy {
1723
2167
  grid-column: 2;
1724
2168
  padding: 0.78rem 0.95rem 0.85rem;
1725
2169
  }
1726
2170
 
2171
+ .race-data-panel--with-telemetry .race-data-copy {
2172
+ grid-column: 2;
2173
+ padding-bottom: 0.35rem;
2174
+ }
2175
+
2176
+ .race-data-telemetry {
2177
+ grid-column: 1 / -1;
2178
+ grid-row: 2;
2179
+ padding: 0 0.95rem 0.75rem;
2180
+ border-left: 0;
2181
+ }
2182
+
2183
+ .race-data-panel--with-telemetry .race-data-link {
2184
+ grid-column: 1 / -1;
2185
+ }
2186
+
1727
2187
  .race-data-panel.is-radio-mode .race-data-copy {
1728
2188
  grid-column: 1;
1729
2189
  padding-left: 0.95rem;
@@ -1816,3 +2276,36 @@
1816
2276
  display: none;
1817
2277
  }
1818
2278
  }
2279
+
2280
+ @media (max-width: 520px) {
2281
+ .sim-canvas-panel--with-timing-tower {
2282
+ min-height: max(58svh, calc(min(46svh, 420px) + 17rem));
2283
+ }
2284
+
2285
+ .sim-canvas-panel--with-timing-tower > .sim-timing {
2286
+ position: static;
2287
+ inset: auto;
2288
+ width: 100%;
2289
+ max-width: 100%;
2290
+ height: min(46svh, 420px);
2291
+ clip-path: none;
2292
+ }
2293
+
2294
+ .sim-canvas-panel--with-timing-tower > .sim-timing.broadcast-tower {
2295
+ position: static;
2296
+ width: 100%;
2297
+ max-width: 100%;
2298
+ height: min(46svh, 420px);
2299
+ }
2300
+
2301
+ .sim-canvas-panel--with-timing-tower > .camera-controls {
2302
+ left: 0.75rem;
2303
+ top: calc(min(46svh, 420px) + 1.25rem);
2304
+ max-width: calc(100% - 1.5rem);
2305
+ }
2306
+
2307
+ .sim-canvas-panel--with-timing-tower > .start-lights {
2308
+ top: calc(min(46svh, 420px) + 4.2rem);
2309
+ left: 50%;
2310
+ }
2311
+ }