@jgengine/shell 0.10.0 → 0.12.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 (286) hide show
  1. package/CHANGELOG.md +39 -2
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/CombatPresentation.d.ts +5 -0
  5. package/dist/CombatPresentation.js +8 -0
  6. package/dist/GameHost.d.ts +25 -1
  7. package/dist/GameHost.js +60 -4
  8. package/dist/GamePhaseStamp.d.ts +1 -0
  9. package/dist/GamePhaseStamp.js +9 -0
  10. package/dist/GamePlayer.d.ts +5 -0
  11. package/dist/GamePlayer.js +5 -0
  12. package/dist/GamePlayerShell.d.ts +5 -12
  13. package/dist/GamePlayerShell.js +67 -1332
  14. package/dist/GameUiPreview.js +3 -2
  15. package/dist/Shell3dPresentation.d.ts +63 -0
  16. package/dist/Shell3dPresentation.js +302 -0
  17. package/dist/ShellChrome.d.ts +51 -0
  18. package/dist/ShellChrome.js +51 -0
  19. package/dist/ShellHudPresentation.d.ts +41 -0
  20. package/dist/ShellHudPresentation.js +22 -0
  21. package/dist/audio/audioEngine.d.ts +4 -0
  22. package/dist/audio/audioEngine.js +128 -21
  23. package/dist/audio/audioWire.d.ts +40 -0
  24. package/dist/audio/audioWire.js +62 -0
  25. package/dist/audio/loopParams.d.ts +20 -0
  26. package/dist/audio/loopParams.js +28 -0
  27. package/dist/behaviour.d.ts +2 -1
  28. package/dist/behaviour.js +2 -1
  29. package/dist/behaviourAttach.d.ts +1 -0
  30. package/dist/behaviourAttach.js +1 -0
  31. package/dist/behaviourDriver.d.ts +1 -0
  32. package/dist/behaviourDriver.js +1 -0
  33. package/dist/boundActionDispatch.d.ts +13 -0
  34. package/dist/boundActionDispatch.js +37 -0
  35. package/dist/camera/GameCameraRig.d.ts +5 -2
  36. package/dist/camera/GameCameraRig.js +8 -3
  37. package/dist/camera/GameFirstPersonCamera.d.ts +9 -2
  38. package/dist/camera/GameFirstPersonCamera.js +8 -3
  39. package/dist/camera/GameInspectionCamera.d.ts +1 -1
  40. package/dist/camera/GameInspectionCamera.js +2 -2
  41. package/dist/camera/GameOrbitCamera.js +24 -9
  42. package/dist/camera/cameraBlendMath.d.ts +3 -0
  43. package/dist/camera/cameraBlendMath.js +3 -0
  44. package/dist/camera/cameraRigs.d.ts +3 -1
  45. package/dist/camera/cameraRigs.js +21 -3
  46. package/dist/camera/fovPreference.d.ts +6 -1
  47. package/dist/camera/fovPreference.js +6 -1
  48. package/dist/camera/index.d.ts +4 -7
  49. package/dist/camera/index.js +4 -7
  50. package/dist/camera/inspectionCameraMath.d.ts +7 -2
  51. package/dist/camera/inspectionCameraMath.js +7 -2
  52. package/dist/camera/orbitCameraMath.d.ts +36 -6
  53. package/dist/camera/orbitCameraMath.js +56 -6
  54. package/dist/camera/rigMath.d.ts +114 -24
  55. package/dist/camera/rigMath.js +129 -24
  56. package/dist/camera/rigResolve.d.ts +4 -2
  57. package/dist/camera/rigResolve.js +4 -2
  58. package/dist/camera/shakeChannel.d.ts +6 -2
  59. package/dist/camera/shakeChannel.js +6 -2
  60. package/dist/camera/shakeChannelMath.d.ts +1 -0
  61. package/dist/camera/shakeChannelMath.js +1 -0
  62. package/dist/commandSink.d.ts +8 -3
  63. package/dist/commandSink.js +8 -3
  64. package/dist/defineGame.d.ts +15 -1
  65. package/dist/defineGame.js +50 -9
  66. package/dist/devtools/ColPanel.d.ts +1 -0
  67. package/dist/devtools/ColPanel.js +14 -0
  68. package/dist/devtools/DevtoolsOverlay.d.ts +11 -7
  69. package/dist/devtools/DevtoolsOverlay.js +47 -462
  70. package/dist/devtools/KeysPanel.d.ts +4 -0
  71. package/dist/devtools/KeysPanel.js +31 -0
  72. package/dist/devtools/LogsPanel.d.ts +1 -0
  73. package/dist/devtools/LogsPanel.js +12 -0
  74. package/dist/devtools/NetPanel.d.ts +4 -0
  75. package/dist/devtools/NetPanel.js +10 -0
  76. package/dist/devtools/PerfPanel.d.ts +4 -0
  77. package/dist/devtools/PerfPanel.js +53 -0
  78. package/dist/devtools/TunePanel.d.ts +3 -0
  79. package/dist/devtools/TunePanel.js +309 -0
  80. package/dist/devtools/agentBridge.d.ts +41 -0
  81. package/dist/devtools/agentBridge.js +266 -0
  82. package/dist/devtools/collisionDebug.d.ts +6 -0
  83. package/dist/devtools/collisionDebug.js +6 -0
  84. package/dist/devtools/collisionDebugMath.d.ts +8 -2
  85. package/dist/devtools/collisionDebugMath.js +24 -5
  86. package/dist/devtools/devtoolsOverrides.d.ts +6 -0
  87. package/dist/devtools/devtoolsOverrides.js +48 -0
  88. package/dist/devtools/panelAtoms.d.ts +9 -0
  89. package/dist/devtools/panelAtoms.js +10 -0
  90. package/dist/devtools/perfDiagnose.d.ts +2 -0
  91. package/dist/devtools/perfDiagnose.js +43 -0
  92. package/dist/diagnostics/RuntimeDiagnostics.d.ts +36 -0
  93. package/dist/diagnostics/RuntimeDiagnostics.js +80 -0
  94. package/dist/drivers/FrameDriver.d.ts +37 -0
  95. package/dist/drivers/FrameDriver.js +232 -0
  96. package/dist/drivers/HudOnlyDriver.d.ts +16 -0
  97. package/dist/drivers/HudOnlyDriver.js +60 -0
  98. package/dist/environment/Daylight.d.ts +23 -7
  99. package/dist/environment/Daylight.js +106 -13
  100. package/dist/environment/EnvironmentScene.js +44 -9
  101. package/dist/environment/VolumetricClouds.d.ts +17 -0
  102. package/dist/environment/VolumetricClouds.js +202 -0
  103. package/dist/environment/daylightCycle.d.ts +3 -1
  104. package/dist/environment/daylightCycle.js +3 -1
  105. package/dist/environment/groundPadMath.d.ts +3 -0
  106. package/dist/environment/groundPadMath.js +3 -0
  107. package/dist/environment/index.d.ts +1 -0
  108. package/dist/environment/index.js +1 -0
  109. package/dist/environment/skyLightingPolicy.d.ts +2 -0
  110. package/dist/environment/skyLightingPolicy.js +2 -0
  111. package/dist/environment/terrainGroundColor.d.ts +9 -0
  112. package/dist/environment/terrainGroundColor.js +22 -0
  113. package/dist/gameKit.d.ts +27 -0
  114. package/dist/gameKit.js +29 -0
  115. package/dist/hotbarActions.d.ts +26 -0
  116. package/dist/hotbarActions.js +27 -0
  117. package/dist/inputSink.d.ts +16 -4
  118. package/dist/inputSink.js +57 -7
  119. package/dist/map/MapMarkerBeacons.d.ts +3 -2
  120. package/dist/materialOverride.d.ts +10 -0
  121. package/dist/materialOverride.js +15 -3
  122. package/dist/multiplayer.js +8 -2
  123. package/dist/postfx/PostProcessing.d.ts +9 -1
  124. package/dist/postfx/PostProcessing.js +56 -11
  125. package/dist/postfx/gradeShader.js +9 -1
  126. package/dist/presentationResolve.d.ts +35 -0
  127. package/dist/presentationResolve.js +51 -0
  128. package/dist/registry.d.ts +4 -2
  129. package/dist/render/EnvironmentLighting.d.ts +10 -0
  130. package/dist/render/EnvironmentLighting.js +34 -0
  131. package/dist/render/SceneLighting.d.ts +7 -0
  132. package/dist/render/SceneLighting.js +18 -0
  133. package/dist/render/SceneModels.d.ts +14 -0
  134. package/dist/render/SceneModels.js +337 -0
  135. package/dist/render/assetBase.d.ts +17 -0
  136. package/dist/render/assetBase.js +35 -0
  137. package/dist/render/defaultSurface.d.ts +29 -0
  138. package/dist/render/defaultSurface.js +101 -0
  139. package/dist/render/modelLoad.d.ts +24 -0
  140. package/dist/render/modelLoad.js +76 -0
  141. package/dist/render/modelRender.d.ts +11 -0
  142. package/dist/render/modelRender.js +15 -0
  143. package/dist/render/resolveModel.d.ts +54 -3
  144. package/dist/render/resolveModel.js +116 -4
  145. package/dist/render/useEntityRenderCues.d.ts +13 -0
  146. package/dist/render/useEntityRenderCues.js +62 -0
  147. package/dist/scatter/InstancedScatter.d.ts +24 -0
  148. package/dist/scatter/InstancedScatter.js +135 -0
  149. package/dist/scatter/scatterModels.d.ts +25 -0
  150. package/dist/scatter/scatterModels.js +61 -0
  151. package/dist/scatter/scatterProxies.d.ts +6 -0
  152. package/dist/scatter/scatterProxies.js +118 -0
  153. package/dist/scatter.d.ts +1 -0
  154. package/dist/scatter.js +1 -0
  155. package/dist/scene/AuthoredScene.d.ts +84 -0
  156. package/dist/scene/AuthoredScene.js +178 -0
  157. package/dist/scene/CityRenderer.d.ts +2 -0
  158. package/dist/scene/CityRenderer.js +1031 -0
  159. package/dist/scene/GeneratedAssetRenderer.d.ts +14 -0
  160. package/dist/scene/GeneratedAssetRenderer.js +59 -0
  161. package/dist/scene/GrassFieldRenderer.d.ts +2 -0
  162. package/dist/scene/GrassFieldRenderer.js +73 -0
  163. package/dist/scene/PoleLineRenderer.d.ts +2 -0
  164. package/dist/scene/PoleLineRenderer.js +287 -0
  165. package/dist/scene/SoilPatchRenderer.d.ts +2 -0
  166. package/dist/scene/SoilPatchRenderer.js +84 -0
  167. package/dist/scene/StudioStage.d.ts +37 -0
  168. package/dist/scene/StudioStage.js +42 -0
  169. package/dist/scene/WaterRenderer.d.ts +2 -0
  170. package/dist/scene/WaterRenderer.js +61 -0
  171. package/dist/scene/builtinSceneKindRenderers.d.ts +2 -0
  172. package/dist/scene/builtinSceneKindRenderers.js +26 -0
  173. package/dist/scene/cityWindowMaterial.d.ts +16 -0
  174. package/dist/scene/cityWindowMaterial.js +81 -0
  175. package/dist/scene/sceneKindRenderers.d.ts +30 -0
  176. package/dist/scene/sceneKindRenderers.js +17 -0
  177. package/dist/scene.d.ts +1 -0
  178. package/dist/scene.js +1 -0
  179. package/dist/settings/appliedSettings.d.ts +7 -1
  180. package/dist/settings/appliedSettings.js +13 -2
  181. package/dist/settings/settingsController.d.ts +2 -0
  182. package/dist/settings/settingsController.js +22 -1
  183. package/dist/shellConstants.d.ts +4 -0
  184. package/dist/shellConstants.js +4 -0
  185. package/dist/shellMovement.d.ts +8 -0
  186. package/dist/shellMovement.js +11 -0
  187. package/dist/shellPointer.d.ts +20 -0
  188. package/dist/shellPointer.js +28 -0
  189. package/dist/structures/PlacementGhost.d.ts +4 -0
  190. package/dist/structures/PlacementGhost.js +4 -0
  191. package/dist/structures/TransformGizmo.d.ts +53 -0
  192. package/dist/structures/TransformGizmo.js +59 -0
  193. package/dist/structures/index.d.ts +1 -0
  194. package/dist/structures/index.js +1 -0
  195. package/dist/terrain/GrassField.d.ts +11 -3
  196. package/dist/terrain/GrassField.js +16 -6
  197. package/dist/terrain/TerraformBrushCursor.js +3 -0
  198. package/dist/terrain/grassBudget.d.ts +11 -2
  199. package/dist/terrain/grassBudget.js +20 -4
  200. package/dist/terrain/grassGeometry.d.ts +35 -0
  201. package/dist/terrain/grassGeometry.js +85 -20
  202. package/dist/terrain/grassMaterial.d.ts +20 -0
  203. package/dist/terrain/grassMaterial.js +68 -13
  204. package/dist/terrain/heightfieldGeometry.d.ts +34 -0
  205. package/dist/terrain/heightfieldGeometry.js +109 -0
  206. package/dist/terrain/index.d.ts +1 -0
  207. package/dist/terrain/index.js +1 -0
  208. package/dist/terrain/random.d.ts +3 -0
  209. package/dist/terrain/random.js +3 -0
  210. package/dist/terrain/soilPatchMaterial.d.ts +23 -0
  211. package/dist/terrain/soilPatchMaterial.js +147 -0
  212. package/dist/terrain/terrainDetailMaterial.d.ts +19 -2
  213. package/dist/terrain/terrainDetailMaterial.js +87 -7
  214. package/dist/terrain/terrainMath.d.ts +8 -1
  215. package/dist/terrain/terrainMath.js +8 -1
  216. package/dist/touch/TouchControlsOverlay.d.ts +9 -5
  217. package/dist/touch/TouchControlsOverlay.js +201 -22
  218. package/dist/useShellMultiplayerSync.d.ts +9 -0
  219. package/dist/useShellMultiplayerSync.js +98 -0
  220. package/dist/visibility/CullingProvider.js +1 -1
  221. package/dist/water/Ocean.d.ts +7 -1
  222. package/dist/water/Ocean.js +16 -3
  223. package/dist/water/OceanConfig.d.ts +11 -0
  224. package/dist/water/OceanConfig.js +8 -0
  225. package/dist/water/OceanMaterial.d.ts +12 -0
  226. package/dist/water/OceanMaterial.js +9 -0
  227. package/dist/water/OceanShader.d.ts +2 -2
  228. package/dist/water/OceanShader.js +78 -10
  229. package/dist/weather/fireSpreadPose.d.ts +1 -0
  230. package/dist/weather/fireSpreadPose.js +1 -0
  231. package/dist/weather/weatherGeometry.d.ts +1 -0
  232. package/dist/weather/weatherGeometry.js +1 -0
  233. package/dist/weather/weatherMath.d.ts +3 -0
  234. package/dist/weather/weatherMath.js +3 -0
  235. package/dist/weather/weatherUniforms.d.ts +3 -0
  236. package/dist/weather/weatherUniforms.js +3 -0
  237. package/dist/world/PlaceScene.d.ts +11 -0
  238. package/dist/world/PlaceScene.js +27 -0
  239. package/dist/world/RetainedVfx.d.ts +10 -0
  240. package/dist/world/RetainedVfx.js +136 -0
  241. package/dist/world/WorldHud.d.ts +49 -2
  242. package/dist/world/WorldHud.js +87 -2
  243. package/dist/world/WorldScene.d.ts +21 -0
  244. package/dist/world/WorldScene.js +186 -0
  245. package/dist/world/WorldVfx.d.ts +9 -0
  246. package/dist/world/WorldVfx.js +184 -0
  247. package/dist/world/entityPose.d.ts +2 -0
  248. package/dist/world/entityPose.js +2 -0
  249. package/dist/world/floatTextStyle.d.ts +1 -0
  250. package/dist/world/floatTextStyle.js +1 -0
  251. package/dist/world/telegraphPulse.d.ts +1 -0
  252. package/dist/world/telegraphPulse.js +1 -0
  253. package/dist/world/worldBarSamples.d.ts +25 -0
  254. package/dist/world/worldBarSamples.js +38 -0
  255. package/dist/worldSky.d.ts +11 -0
  256. package/dist/worldSky.js +21 -0
  257. package/dist/worldSync.d.ts +2 -1
  258. package/dist/worldSync.js +2 -1
  259. package/package.json +6 -6
  260. package/skills/game-design/SKILL.md +28 -0
  261. package/skills/game-design/agents/openai.yaml +4 -0
  262. package/skills/game-design/references/application-playbook.md +170 -0
  263. package/skills/game-design/references/field-guide.md +288 -0
  264. package/skills/jgengine/SKILL.md +54 -0
  265. package/skills/jgengine/api.md +527 -0
  266. package/skills/jgengine/capabilities.md +131 -0
  267. package/skills/jgengine/recipes/minimal-game.md +88 -0
  268. package/skills/jgengine-ui/SKILL.md +41 -0
  269. package/skills/jgengine-ui/api.md +2007 -0
  270. package/skills/jgengine-ui/capabilities.md +211 -0
  271. package/skills/jgengine-ui/recipes/portable-minimap.md +150 -0
  272. package/skills/jgengine-ui/reference.md +513 -0
  273. package/skills/jgengine-ui/references/visual-scorecard.md +73 -0
  274. package/skills/jgengine-world/SKILL.md +51 -0
  275. package/skills/jgengine-world/api.md +3056 -0
  276. package/skills/jgengine-world/capabilities.md +476 -0
  277. package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
  278. package/skills/jgengine-world/reference.md +261 -0
  279. package/skills/level-design/SKILL.md +54 -0
  280. package/skills/level-design/agents/openai.yaml +4 -0
  281. package/skills/level-design/references/application-playbook.md +192 -0
  282. package/skills/level-design/references/field-guide.md +337 -0
  283. package/skills/level-design/references/live-editor-loop.md +179 -0
  284. package/dist/cartridge.d.ts +0 -145
  285. package/dist/cartridge.js +0 -246
  286. package/llms.txt +0 -2761
package/dist/cartridge.js DELETED
@@ -1,246 +0,0 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState, useSyncExternalStore } from "react";
3
- import { useFrame } from "@react-three/fiber";
4
- import { createCartridge } from "@jgengine/core/cartridge/runtime";
5
- import { WASD_KEYBINDS, leveled } from "@jgengine/core/cartridge/spec";
6
- import { validateCartridge } from "@jgengine/core/cartridge/validate";
7
- import { HudCanvas, HudPanel, useHudLayout } from "@jgengine/react";
8
- import { useAbilitySlots, useEntityStat } from "@jgengine/react/hooks";
9
- import { useGameContext } from "@jgengine/react/provider";
10
- import { defineGame } from "./defineGame.js";
11
- function useTick(intervalMs) {
12
- const [, setTick] = useState(0);
13
- useEffect(() => {
14
- const id = window.setInterval(() => setTick((value) => value + 1), intervalMs);
15
- return () => window.clearInterval(id);
16
- }, [intervalMs]);
17
- }
18
- function useRunPhase(ctx, runtime) {
19
- const run = runtime.run(ctx);
20
- useSyncExternalStore(run.subscribe, () => `${run.phase}:${run.pendingOffers?.map((offer) => offer.id).join(",") ?? ""}`);
21
- }
22
- function winSeconds(config) {
23
- return config.rules.win?.kind === "survive" ? config.rules.win.seconds : null;
24
- }
25
- function VitalItem({ config, item }) {
26
- const ctx = useGameContext();
27
- const value = useEntityStat(ctx.player.userId, item.stat);
28
- if (value === null)
29
- return null;
30
- return _jsx(config.panels.Vital, { value: value, label: item.label, tone: item.tone, width: item.width });
31
- }
32
- function XpItem({ config, item }) {
33
- const ctx = useGameContext();
34
- const xp = useEntityStat(ctx.player.userId, "xp");
35
- const level = useEntityStat(ctx.player.userId, "level");
36
- if (xp === null)
37
- return null;
38
- const fraction = (xp.current - xp.min) / Math.max(1, xp.max - xp.min);
39
- return _jsx(config.panels.Xp, { fraction: fraction, level: level?.current, width: item.width });
40
- }
41
- function TimerItem({ config, runtime, item, }) {
42
- const ctx = useGameContext();
43
- const target = winSeconds(config);
44
- const elapsed = runtime.run(ctx).playingSeconds;
45
- const seconds = target === null ? elapsed : Math.max(0, target - elapsed);
46
- return _jsx(config.panels.Timer, { seconds: seconds, label: item.label });
47
- }
48
- function ScoreItem({ config, runtime, item, }) {
49
- const ctx = useGameContext();
50
- return _jsx(config.panels.Score, { value: runtime.run(ctx).kills, label: item.label, digits: item.digits });
51
- }
52
- function AbilityBarItem({ config, runtime, item, }) {
53
- const ctx = useGameContext();
54
- const slots = useAbilitySlots(runtime.weaponKit(ctx));
55
- return (_jsx(config.panels.AbilityBar, { slots: slots.map((slot) => ({
56
- id: slot.id,
57
- icon: item.icons[slot.id] ?? slot.id,
58
- state: slot.state,
59
- cooldownFraction: slot.cooldownFraction,
60
- justCast: slot.justCast,
61
- })) }));
62
- }
63
- function PanelItems({ config, runtime, items, }) {
64
- return (_jsx(_Fragment, { children: items.map((item, index) => {
65
- switch (item.kind) {
66
- case "vital":
67
- return _jsx(VitalItem, { config: config, item: item }, index);
68
- case "xp":
69
- return _jsx(XpItem, { config: config, item: item }, index);
70
- case "timer":
71
- return _jsx(TimerItem, { config: config, runtime: runtime, item: item }, index);
72
- case "score":
73
- return _jsx(ScoreItem, { config: config, runtime: runtime, item: item }, index);
74
- case "abilityBar":
75
- return _jsx(AbilityBarItem, { config: config, runtime: runtime, item: item }, index);
76
- case "component":
77
- return _jsx(item.Component, {}, index);
78
- }
79
- }) }));
80
- }
81
- function WinScreenHost({ config, runtime }) {
82
- const ctx = useGameContext();
83
- const level = useEntityStat(ctx.player.userId, "level");
84
- const win = config.screens.win;
85
- if (win === undefined)
86
- return null;
87
- const run = runtime.run(ctx);
88
- const lines = win.lines.map((line) => ({
89
- label: line.label,
90
- accent: line.accent,
91
- value: "value" in line ? line.value : line.source === "kills" ? run.kills : (level?.current ?? 1),
92
- }));
93
- return _jsx(config.panels.WinScreen, { title: win.title, lines: lines });
94
- }
95
- function DraftModalHost({ config, runtime }) {
96
- const ctx = useGameContext();
97
- const offers = runtime.run(ctx).pendingOffers;
98
- if (offers === null)
99
- return null;
100
- return _jsx(config.panels.DraftModal, { offers: offers, choose: (id) => runtime.chooseUpgrade(ctx, id) });
101
- }
102
- function CartridgeUI({ config, runtime }) {
103
- const ctx = useGameContext();
104
- const layout = useHudLayout({ storageKey: config.hud.storageKey ?? config.name });
105
- useRunPhase(ctx, runtime);
106
- useTick(200);
107
- const run = runtime.run(ctx);
108
- return (_jsxs("div", { style: { ...config.theme, display: "contents" }, children: [run.phase === "start" && (_jsx(config.panels.StartScreen, { title: config.screens.start?.title ?? config.name, subtitle: config.screens.start?.subtitle, buttonLabel: config.screens.start?.buttonLabel, begin: () => runtime.begin(ctx) })), run.phase === "countdown" && _jsx(config.panels.Countdown, { seconds: Math.ceil(run.countdownRemaining) }), run.phase === "lost" && config.screens.lose !== undefined && (_jsx(config.panels.LoseScreen, { title: config.screens.lose.title, subtitle: config.screens.lose.subtitle })), run.phase === "won" && _jsx(WinScreenHost, { config: config, runtime: runtime }), run.phase === "playing" && (_jsxs(HudCanvas, { layout: layout, children: [_jsx(DraftModalHost, { config: config, runtime: runtime }), config.hud.panels.map((panel) => (_jsx(HudPanel, { id: panel.id, anchor: panel.anchor, inset: panel.inset, style: panel.items.length > 1
109
- ? { display: "flex", flexDirection: "column", alignItems: "center", gap: 6 }
110
- : undefined, children: _jsx(PanelItems, { config: config, runtime: runtime, items: panel.items }) }, panel.id)))] }))] }));
111
- }
112
- const MAX_BOLTS = 10;
113
- const MAX_PULSES = 6;
114
- function hideMesh(mesh) {
115
- if (mesh !== null)
116
- mesh.visible = false;
117
- }
118
- function BoltPool({ runtime, weaponId, weapon, }) {
119
- const ctx = useGameContext();
120
- const refs = useRef(new Array(MAX_BOLTS).fill(null));
121
- useFrame(() => {
122
- const run = runtime.run(ctx);
123
- const now = ctx.time.now();
124
- const bolts = run.bolts.filter((bolt) => bolt.weaponId === weaponId);
125
- for (let i = 0; i < MAX_BOLTS; i += 1) {
126
- const mesh = refs.current[i];
127
- const bolt = bolts[i];
128
- if (mesh === null)
129
- continue;
130
- if (bolt === undefined) {
131
- hideMesh(mesh);
132
- continue;
133
- }
134
- const t = Math.min(1, Math.max(0, (now - bolt.firedAt) / bolt.travelSeconds));
135
- mesh.visible = true;
136
- mesh.position.set(bolt.origin[0] + (bolt.target[0] - bolt.origin[0]) * t, bolt.origin[1] + 0.9, bolt.origin[2] + (bolt.target[2] - bolt.origin[2]) * t);
137
- }
138
- });
139
- return (_jsx(_Fragment, { children: Array.from({ length: MAX_BOLTS }, (_, i) => (_jsxs("mesh", { ref: (mesh) => {
140
- refs.current[i] = mesh;
141
- }, visible: false, children: [_jsx("sphereGeometry", { args: [0.16, 8, 8] }), _jsx("meshStandardMaterial", { color: weapon.fxColor ?? "#8be9f0", emissive: weapon.fxEmissive ?? weapon.fxColor ?? "#8be9f0", emissiveIntensity: 1.6 })] }, i))) }));
142
- }
143
- function PulsePool({ runtime, weaponId, weapon, }) {
144
- const ctx = useGameContext();
145
- const refs = useRef(new Array(MAX_PULSES).fill(null));
146
- useFrame(() => {
147
- const run = runtime.run(ctx);
148
- const now = ctx.time.now();
149
- const pulses = run.pulses.filter((pulse) => pulse.weaponId === weaponId);
150
- for (let i = 0; i < MAX_PULSES; i += 1) {
151
- const mesh = refs.current[i];
152
- const pulse = pulses[i];
153
- if (mesh === null)
154
- continue;
155
- if (pulse === undefined) {
156
- hideMesh(mesh);
157
- continue;
158
- }
159
- const t = Math.min(1, Math.max(0, (now - pulse.firedAt) / pulse.durationSeconds));
160
- const radius = Math.max(0.01, pulse.maxRadius * t);
161
- mesh.visible = true;
162
- mesh.position.set(pulse.at[0], pulse.at[1] + 0.05, pulse.at[2]);
163
- mesh.scale.set(radius, radius, radius);
164
- const material = mesh.material;
165
- if (!Array.isArray(material))
166
- material.opacity = 0.55 * (1 - t);
167
- }
168
- });
169
- return (_jsx(_Fragment, { children: Array.from({ length: MAX_PULSES }, (_, i) => (_jsxs("mesh", { ref: (mesh) => {
170
- refs.current[i] = mesh;
171
- }, rotation: [-Math.PI / 2, 0, 0], visible: false, children: [_jsx("ringGeometry", { args: [0.85, 1, 48] }), _jsx("meshBasicMaterial", { color: weapon.fxColor ?? "#a566d9", transparent: true, opacity: 0.5 })] }, i))) }));
172
- }
173
- function OrbitPool({ runtime, weaponId, weapon, }) {
174
- const ctx = useGameContext();
175
- const maxBlades = Math.ceil(leveled(weapon.blades, weapon.maxLevel));
176
- const groupRef = useRef(null);
177
- const refs = useRef(new Array(maxBlades).fill(null));
178
- useFrame(() => {
179
- const run = runtime.run(ctx);
180
- const player = ctx.scene.entity.get(ctx.player.userId);
181
- if (player === null || run.phase !== "playing") {
182
- if (groupRef.current !== null)
183
- groupRef.current.visible = false;
184
- return;
185
- }
186
- const level = run.weaponLevel(weaponId);
187
- const blades = leveled(weapon.blades, level);
188
- const radius = leveled(weapon.radius, level);
189
- const angle = ctx.time.now() * weapon.angularSpeed;
190
- if (groupRef.current !== null)
191
- groupRef.current.visible = true;
192
- for (let i = 0; i < maxBlades; i += 1) {
193
- const mesh = refs.current[i];
194
- if (mesh === null)
195
- continue;
196
- if (i >= blades) {
197
- hideMesh(mesh);
198
- continue;
199
- }
200
- const theta = angle + (i * Math.PI * 2) / blades;
201
- mesh.visible = true;
202
- mesh.position.set(player.position[0] + Math.cos(theta) * radius, player.position[1] + 0.55, player.position[2] + Math.sin(theta) * radius);
203
- }
204
- });
205
- return (_jsx("group", { ref: groupRef, children: Array.from({ length: maxBlades }, (_, i) => (_jsxs("mesh", { ref: (mesh) => {
206
- refs.current[i] = mesh;
207
- }, visible: false, children: [_jsx("boxGeometry", { args: [0.32, 0.08, 0.14] }), _jsx("meshStandardMaterial", { color: weapon.fxColor ?? "#dfe9ea", emissive: weapon.fxEmissive ?? weapon.fxColor ?? "#dfe9ea", emissiveIntensity: 0.8 })] }, i))) }));
208
- }
209
- function CartridgeFxOverlay({ config, runtime }) {
210
- return (_jsx("group", { children: Object.entries(config.weapons).map(([weaponId, weapon]) => {
211
- if (weapon.kind === "projectile") {
212
- return _jsx(BoltPool, { runtime: runtime, weaponId: weaponId, weapon: weapon }, weaponId);
213
- }
214
- if (weapon.kind === "pulse") {
215
- return _jsx(PulsePool, { runtime: runtime, weaponId: weaponId, weapon: weapon }, weaponId);
216
- }
217
- if (weapon.kind === "orbit") {
218
- return _jsx(OrbitPool, { runtime: runtime, weaponId: weaponId, weapon: weapon }, weaponId);
219
- }
220
- return null;
221
- }) }));
222
- }
223
- export function cartridge(config) {
224
- const problems = validateCartridge(config);
225
- if (problems.length > 0) {
226
- throw new Error(`cartridge "${config.name}": invalid spec:\n${problems.map((p) => ` - ${p}`).join("\n")}`);
227
- }
228
- const runtime = createCartridge(config);
229
- return defineGame({
230
- name: config.name,
231
- assets: config.assets,
232
- features: { leaderboard: config.rules.killLeaderboardStat !== undefined },
233
- world: config.world,
234
- physics: config.physics,
235
- input: config.input ?? WASD_KEYBINDS,
236
- save: config.save ?? "none",
237
- content: runtime.content,
238
- loop: runtime.loop,
239
- GameUI: () => _jsx(CartridgeUI, { config: config, runtime: runtime }),
240
- WorldOverlay: () => _jsx(CartridgeFxOverlay, { config: config, runtime: runtime }),
241
- camera: config.camera,
242
- entitySprites: config.entitySprites,
243
- worldItem: config.worldItem,
244
- settings: config.settings,
245
- });
246
- }