@vgai/editor 0.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.
Files changed (519) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +35 -0
  3. package/dist/a/b/c/test-nested.json +1 -0
  4. package/dist/assets/CCDIKSolver-Dz-ysxZF.js +1 -0
  5. package/dist/assets/SelectionBox-BXsv_6aH.js +1 -0
  6. package/dist/assets/browser-project-scripts-DOru4L1x.js +2 -0
  7. package/dist/assets/browserAll-CEkWYlFk.js +1 -0
  8. package/dist/assets/collision-world-DniMB0qq.glb +0 -0
  9. package/dist/assets/create-runtime-DYIWr3va.js +1 -0
  10. package/dist/assets/data-asset-Bb9sIM7i.js +5 -0
  11. package/dist/assets/esbuild-BHljloGq.wasm +0 -0
  12. package/dist/assets/fake-three-BMTQ9rl_.js +1 -0
  13. package/dist/assets/game-8SDZPPgH.js +1 -0
  14. package/dist/assets/game-BI111o5f.js +10 -0
  15. package/dist/assets/game-CevorxyV.js +1 -0
  16. package/dist/assets/game-Di1H0gFj.js +1 -0
  17. package/dist/assets/game-Di7XlywD.js +1 -0
  18. package/dist/assets/game-DjnCaw8R.js +1 -0
  19. package/dist/assets/game-Q9A0aXSV.js +1 -0
  20. package/dist/assets/game-pt_1lQLv.js +1 -0
  21. package/dist/assets/game-source-CvidN7AB.js +1 -0
  22. package/dist/assets/game-xsOho_wg.js +83 -0
  23. package/dist/assets/index-Bp5cecD6.js +12 -0
  24. package/dist/assets/index-CPVV6pjw.js +1 -0
  25. package/dist/assets/index-CpOnYyeD.js +213 -0
  26. package/dist/assets/index-Cs8xwv3e.js +1 -0
  27. package/dist/assets/index-DL7RcQ0n.js +27 -0
  28. package/dist/assets/index-Dr8H_6Rl.js +1 -0
  29. package/dist/assets/index-_bCaipUk.js +13650 -0
  30. package/dist/assets/ingest-siblings-Dz8eEqrV.js +1 -0
  31. package/dist/assets/mount-manifest-Bhk0ohsl.js +1 -0
  32. package/dist/assets/recast-navigation.wasm-compat-CvP4UGK6.js +1 -0
  33. package/dist/assets/scene-query-BivAHhJu.js +1 -0
  34. package/dist/assets/stats.module--VATS4Kh.js +1 -0
  35. package/dist/assets/webworkerAll-BLrH0F6F.js +1 -0
  36. package/dist/assets/xstate-animation-binding-1NGLmw6y.js +1 -0
  37. package/dist/assets/xstate.esm-BgUD33nl.js +3 -0
  38. package/dist/index.html +37 -0
  39. package/dist/ingest/racing-game/UPSTREAM.md +68 -0
  40. package/dist/ingest/racing-game/a/Inter-Black.woff +0 -0
  41. package/dist/ingest/racing-game/a/Inter-Black.woff2 +0 -0
  42. package/dist/ingest/racing-game/a/Inter-BlackItalic.woff +0 -0
  43. package/dist/ingest/racing-game/a/Inter-BlackItalic.woff2 +0 -0
  44. package/dist/ingest/racing-game/a/Inter-Bold.woff +0 -0
  45. package/dist/ingest/racing-game/a/Inter-Bold.woff2 +0 -0
  46. package/dist/ingest/racing-game/a/Inter-BoldItalic.woff +0 -0
  47. package/dist/ingest/racing-game/a/Inter-BoldItalic.woff2 +0 -0
  48. package/dist/ingest/racing-game/a/Inter-ExtraBold.woff +0 -0
  49. package/dist/ingest/racing-game/a/Inter-ExtraBold.woff2 +0 -0
  50. package/dist/ingest/racing-game/a/Inter-ExtraBoldItalic.woff +0 -0
  51. package/dist/ingest/racing-game/a/Inter-ExtraBoldItalic.woff2 +0 -0
  52. package/dist/ingest/racing-game/a/Inter-ExtraLight.woff +0 -0
  53. package/dist/ingest/racing-game/a/Inter-ExtraLight.woff2 +0 -0
  54. package/dist/ingest/racing-game/a/Inter-ExtraLightItalic.woff +0 -0
  55. package/dist/ingest/racing-game/a/Inter-ExtraLightItalic.woff2 +0 -0
  56. package/dist/ingest/racing-game/a/Inter-Italic.woff +0 -0
  57. package/dist/ingest/racing-game/a/Inter-Italic.woff2 +0 -0
  58. package/dist/ingest/racing-game/a/Inter-Light.woff +0 -0
  59. package/dist/ingest/racing-game/a/Inter-Light.woff2 +0 -0
  60. package/dist/ingest/racing-game/a/Inter-LightItalic.woff +0 -0
  61. package/dist/ingest/racing-game/a/Inter-LightItalic.woff2 +0 -0
  62. package/dist/ingest/racing-game/a/Inter-Medium.woff +0 -0
  63. package/dist/ingest/racing-game/a/Inter-Medium.woff2 +0 -0
  64. package/dist/ingest/racing-game/a/Inter-MediumItalic.woff +0 -0
  65. package/dist/ingest/racing-game/a/Inter-MediumItalic.woff2 +0 -0
  66. package/dist/ingest/racing-game/a/Inter-Regular.woff +0 -0
  67. package/dist/ingest/racing-game/a/Inter-Regular.woff2 +0 -0
  68. package/dist/ingest/racing-game/a/Inter-SemiBold.woff +0 -0
  69. package/dist/ingest/racing-game/a/Inter-SemiBold.woff2 +0 -0
  70. package/dist/ingest/racing-game/a/Inter-SemiBoldItalic.woff +0 -0
  71. package/dist/ingest/racing-game/a/Inter-SemiBoldItalic.woff2 +0 -0
  72. package/dist/ingest/racing-game/a/Inter-Thin.woff +0 -0
  73. package/dist/ingest/racing-game/a/Inter-Thin.woff2 +0 -0
  74. package/dist/ingest/racing-game/a/Inter-ThinItalic.woff +0 -0
  75. package/dist/ingest/racing-game/a/Inter-ThinItalic.woff2 +0 -0
  76. package/dist/ingest/racing-game/a/Inter-italic.var.woff2 +0 -0
  77. package/dist/ingest/racing-game/a/Inter-roman.var.woff2 +0 -0
  78. package/dist/ingest/racing-game/a/Inter.var.woff2 +0 -0
  79. package/dist/ingest/racing-game/a/index.css +1 -0
  80. package/dist/ingest/racing-game/images/bronze.png +0 -0
  81. package/dist/ingest/racing-game/images/gold.png +0 -0
  82. package/dist/ingest/racing-game/images/silver.png +0 -0
  83. package/dist/ingest/racing-game/index.html +15 -0
  84. package/dist/ingest/racing-game/models/chassis-draco.glb +0 -0
  85. package/dist/ingest/racing-game/models/track-draco.glb +0 -0
  86. package/dist/ingest/racing-game/models/wheel-draco.glb +0 -0
  87. package/dist/ingest/racing-game/rg-entry.js +1 -0
  88. package/dist/ingest/racing-game/sounds/accelerate.mp3 +0 -0
  89. package/dist/ingest/racing-game/sounds/boost.mp3 +0 -0
  90. package/dist/ingest/racing-game/sounds/crash.mp3 +0 -0
  91. package/dist/ingest/racing-game/sounds/engine.mp3 +0 -0
  92. package/dist/ingest/racing-game/sounds/honk.mp3 +0 -0
  93. package/dist/ingest/racing-game/sounds/tire-brake.mp3 +0 -0
  94. package/dist/ingest/racing-game/sounds/train.mp3 +0 -0
  95. package/dist/ingest/racing-game/sounds/water.mp3 +0 -0
  96. package/dist/ingest/racing-game/textures/cursor.svg +3 -0
  97. package/dist/ingest/racing-game/textures/dikhololo_night_1k.hdr +0 -0
  98. package/dist/ingest/racing-game/textures/heightmap_1024.png +0 -0
  99. package/dist/ingest/racing-game/textures/mask.svg +11 -0
  100. package/dist/ingest/racing-game/textures/no_sound.png +0 -0
  101. package/dist/ingest/racing-game/three-r139.module.js +50617 -0
  102. package/dist/ingest/racing-game/vendor.js +179 -0
  103. package/dist/ingest/racing-game/vgai.game.json +20 -0
  104. package/dist/ingest/simcity/UPSTREAM.md +65 -0
  105. package/dist/ingest/simcity/favicon.ico +0 -0
  106. package/dist/ingest/simcity/fonts/Bebas-Regular.otf +0 -0
  107. package/dist/ingest/simcity/fonts/Digitalt.otf +0 -0
  108. package/dist/ingest/simcity/fonts/Stanberry.ttf +0 -0
  109. package/dist/ingest/simcity/icons/bulldozer-color.png +0 -0
  110. package/dist/ingest/simcity/icons/bulldozer.png +0 -0
  111. package/dist/ingest/simcity/icons/calendar.png +0 -0
  112. package/dist/ingest/simcity/icons/factory-color.png +0 -0
  113. package/dist/ingest/simcity/icons/factory.png +0 -0
  114. package/dist/ingest/simcity/icons/house-color.png +0 -0
  115. package/dist/ingest/simcity/icons/house.png +0 -0
  116. package/dist/ingest/simcity/icons/job.png +0 -0
  117. package/dist/ingest/simcity/icons/office.png +0 -0
  118. package/dist/ingest/simcity/icons/pause-color.png +0 -0
  119. package/dist/ingest/simcity/icons/pause.png +0 -0
  120. package/dist/ingest/simcity/icons/person.png +0 -0
  121. package/dist/ingest/simcity/icons/play-color.png +0 -0
  122. package/dist/ingest/simcity/icons/play.png +0 -0
  123. package/dist/ingest/simcity/icons/power-color.png +0 -0
  124. package/dist/ingest/simcity/icons/power-line-color.png +0 -0
  125. package/dist/ingest/simcity/icons/power.png +0 -0
  126. package/dist/ingest/simcity/icons/road-color.png +0 -0
  127. package/dist/ingest/simcity/icons/road.png +0 -0
  128. package/dist/ingest/simcity/icons/select-color.png +0 -0
  129. package/dist/ingest/simcity/icons/select.png +0 -0
  130. package/dist/ingest/simcity/icons/store-color.png +0 -0
  131. package/dist/ingest/simcity/index.html +94 -0
  132. package/dist/ingest/simcity/index.js +58 -0
  133. package/dist/ingest/simcity/main.css +233 -0
  134. package/dist/ingest/simcity/models/armored-truck.glb +0 -0
  135. package/dist/ingest/simcity/models/building-block-4floor-corner.glb +0 -0
  136. package/dist/ingest/simcity/models/building-block-4floor-short.glb +0 -0
  137. package/dist/ingest/simcity/models/building-block-5floor.glb +0 -0
  138. package/dist/ingest/simcity/models/building-burger-joint.glb +0 -0
  139. package/dist/ingest/simcity/models/building-cafe.glb +0 -0
  140. package/dist/ingest/simcity/models/building-casino.glb +0 -0
  141. package/dist/ingest/simcity/models/building-cinema.glb +0 -0
  142. package/dist/ingest/simcity/models/building-house-block-big.glb +0 -0
  143. package/dist/ingest/simcity/models/building-house-family-large.glb +0 -0
  144. package/dist/ingest/simcity/models/building-house-family-small.glb +0 -0
  145. package/dist/ingest/simcity/models/building-office-balcony.glb +0 -0
  146. package/dist/ingest/simcity/models/building-office-big.glb +0 -0
  147. package/dist/ingest/simcity/models/building-office-pyramid.glb +0 -0
  148. package/dist/ingest/simcity/models/building-office-tall.glb +0 -0
  149. package/dist/ingest/simcity/models/building-office.glb +0 -0
  150. package/dist/ingest/simcity/models/building-restaurant.glb +0 -0
  151. package/dist/ingest/simcity/models/building-skyscraper.glb +0 -0
  152. package/dist/ingest/simcity/models/car-ambulance-pickup.glb +0 -0
  153. package/dist/ingest/simcity/models/car-baywatch.glb +0 -0
  154. package/dist/ingest/simcity/models/car-hippie-van.glb +0 -0
  155. package/dist/ingest/simcity/models/car-passenger-race.glb +0 -0
  156. package/dist/ingest/simcity/models/car-passenger.glb +0 -0
  157. package/dist/ingest/simcity/models/car-police.glb +0 -0
  158. package/dist/ingest/simcity/models/car-taxi.glb +0 -0
  159. package/dist/ingest/simcity/models/car-tow-truck.glb +0 -0
  160. package/dist/ingest/simcity/models/car-truck-dump.glb +0 -0
  161. package/dist/ingest/simcity/models/car-veteran.glb +0 -0
  162. package/dist/ingest/simcity/models/construction-small.glb +0 -0
  163. package/dist/ingest/simcity/models/data-center.glb +0 -0
  164. package/dist/ingest/simcity/models/industry-factory-old.glb +0 -0
  165. package/dist/ingest/simcity/models/industry-factory.glb +0 -0
  166. package/dist/ingest/simcity/models/industry-refinery.glb +0 -0
  167. package/dist/ingest/simcity/models/industry-warehouse.glb +0 -0
  168. package/dist/ingest/simcity/models/power_line_pole_modified.glb +0 -0
  169. package/dist/ingest/simcity/models/tile-plain_grass.glb +0 -0
  170. package/dist/ingest/simcity/models/tile-road-curve.glb +0 -0
  171. package/dist/ingest/simcity/models/tile-road-end.glb +0 -0
  172. package/dist/ingest/simcity/models/tile-road-intersection-t.glb +0 -0
  173. package/dist/ingest/simcity/models/tile-road-intersection.glb +0 -0
  174. package/dist/ingest/simcity/models/tile-road-straight.glb +0 -0
  175. package/dist/ingest/simcity/models/truck.glb +0 -0
  176. package/dist/ingest/simcity/statusIcons/no-power.png +0 -0
  177. package/dist/ingest/simcity/statusIcons/no-road-access.png +0 -0
  178. package/dist/ingest/simcity/textures/base.png +0 -0
  179. package/dist/ingest/simcity/textures/grid.png +0 -0
  180. package/dist/ingest/simcity/textures/specular.png +0 -0
  181. package/dist/ingest/simcity/three-r155.module.js +51466 -0
  182. package/dist/ingest/simcity/vgai.game.json +20 -0
  183. package/dist/ingest/tanks/UPSTREAM.md +69 -0
  184. package/dist/ingest/tanks/index.html +214 -0
  185. package/dist/ingest/tanks/models/pixelTank.fbx +0 -0
  186. package/dist/ingest/tanks/tanks-entry.js +92 -0
  187. package/dist/ingest/tanks/three-r170.module.js +54571 -0
  188. package/dist/ingest/tanks/vgai.game.json +20 -0
  189. package/dist/inputmaps/default.inputmap.json +41 -0
  190. package/dist/jsm/libs/draco/gltf/draco_decoder.js +33 -0
  191. package/dist/jsm/libs/draco/gltf/draco_decoder.wasm +0 -0
  192. package/dist/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -0
  193. package/dist/scenes/untitled.vscn.json +29 -0
  194. package/dist/textures/waternormals.jpg +0 -0
  195. package/dist-server/packaged.mjs +18155 -0
  196. package/package.json +36 -0
  197. package/server/asset-library-routes.ts +833 -0
  198. package/server/canonical-path.ts +50 -0
  199. package/server/cloud-asset-catalog.ts +101 -0
  200. package/server/dev.ts +350 -0
  201. package/server/editor-server.ts +1537 -0
  202. package/server/editor-sse.ts +73 -0
  203. package/server/game-globals-shadow.ts +58 -0
  204. package/server/local-asset-catalog.ts +163 -0
  205. package/server/packaged.ts +571 -0
  206. package/server/prod.ts +75 -0
  207. package/server/project-optimize-deps-entries.ts +149 -0
  208. package/server/project-view.ts +65 -0
  209. package/server/server-utils.ts +430 -0
  210. package/server/session-registry.ts +93 -0
  211. package/src/EditorContext.tsx +87 -0
  212. package/src/achieved-tier.ts +126 -0
  213. package/src/action-registry.ts +268 -0
  214. package/src/adapter-resolver.ts +1858 -0
  215. package/src/asset-events.ts +100 -0
  216. package/src/authoring/active-adapter.ts +98 -0
  217. package/src/authoring/active-systems.ts +50 -0
  218. package/src/authoring/boundary-authoring-adapter.ts +178 -0
  219. package/src/authoring/composite-authoring-adapter.ts +891 -0
  220. package/src/authoring/design-time-layers.ts +776 -0
  221. package/src/authoring/edit-mode-authoring.ts +643 -0
  222. package/src/authoring/embed-only-adapter.ts +57 -0
  223. package/src/authoring/ephemeral-persistence.ts +26 -0
  224. package/src/authoring/eyedropper-session.ts +69 -0
  225. package/src/authoring/first-party-hierarchy-menu.ts +74 -0
  226. package/src/authoring/first-party-inspector/AddSectionMenu.tsx +118 -0
  227. package/src/authoring/first-party-inspector/EnvironmentSection.tsx +550 -0
  228. package/src/authoring/first-party-inspector/HeaderSection.tsx +329 -0
  229. package/src/authoring/first-party-inspector/is-first-party-selection.ts +44 -0
  230. package/src/authoring/first-party-inspector/register.tsx +108 -0
  231. package/src/authoring/ingest-authoring-adapter.ts +475 -0
  232. package/src/authoring/ingest-capture.ts +94 -0
  233. package/src/authoring/ingest-game-adapter.ts +291 -0
  234. package/src/authoring/ingest-iframe-adapter.ts +38 -0
  235. package/src/authoring/ingest-iframe-reachable-adapter.ts +401 -0
  236. package/src/authoring/ingest-overlay.ts +193 -0
  237. package/src/authoring/layered-pick.ts +87 -0
  238. package/src/authoring/mount-failure-report.ts +112 -0
  239. package/src/authoring/overlay-report.ts +52 -0
  240. package/src/authoring/project-scenes.ts +111 -0
  241. package/src/authoring/react-dom-authoring-adapter.ts +795 -0
  242. package/src/authoring/react-inspector-section.tsx +1041 -0
  243. package/src/authoring/react-world-authoring-adapter.ts +2400 -0
  244. package/src/authoring/root-activation.ts +61 -0
  245. package/src/authoring/scene-ui-layer.ts +485 -0
  246. package/src/authoring/story-overlay.ts +48 -0
  247. package/src/authoring/ui-authoring-adapter.ts +325 -0
  248. package/src/authoring/ui-hierarchy-menu.ts +40 -0
  249. package/src/authoring/ui-inspector-sections.tsx +156 -0
  250. package/src/authoring/undo-timeline.ts +145 -0
  251. package/src/authoring/vgai-scene-authoring-adapter.ts +746 -0
  252. package/src/authoring/viewport-pick-context.ts +31 -0
  253. package/src/authoring/viewport-raycast.ts +80 -0
  254. package/src/authoring/world-overlay.ts +76 -0
  255. package/src/authoring/world-pan-state.ts +115 -0
  256. package/src/authoring/world-session-state.ts +102 -0
  257. package/src/authoring/world2d-authoring-adapter.ts +313 -0
  258. package/src/browser-external-watch.ts +98 -0
  259. package/src/browser-play-entry.ts +112 -0
  260. package/src/browser-project-scripts.ts +112 -0
  261. package/src/browser-transpile.ts +246 -0
  262. package/src/browser-watch-reload.ts +100 -0
  263. package/src/command-listener.ts +326 -0
  264. package/src/components/AlignToolbar.tsx +189 -0
  265. package/src/components/AppRoot.tsx +73 -0
  266. package/src/components/AssetBrowser.tsx +502 -0
  267. package/src/components/BottomPanel.tsx +326 -0
  268. package/src/components/BuildPanel.tsx +455 -0
  269. package/src/components/CameraInfo.tsx +56 -0
  270. package/src/components/CommandPalette.tsx +265 -0
  271. package/src/components/ConsolePanel.tsx +272 -0
  272. package/src/components/DataPanel.tsx +1268 -0
  273. package/src/components/DefaultEditorLayout.tsx +509 -0
  274. package/src/components/FolderTree.tsx +179 -0
  275. package/src/components/GameHierarchy.tsx +1349 -0
  276. package/src/components/Inspector.tsx +671 -0
  277. package/src/components/InspectorToolSection.tsx +74 -0
  278. package/src/components/MountFailureBanner.tsx +110 -0
  279. package/src/components/NetworkSection.tsx +109 -0
  280. package/src/components/OnlineAssetBrowser.tsx +448 -0
  281. package/src/components/OverlayReportBanner.tsx +122 -0
  282. package/src/components/PlayBar.tsx +356 -0
  283. package/src/components/PrefabSaveDialog.tsx +201 -0
  284. package/src/components/ProjectHeader.tsx +174 -0
  285. package/src/components/ProjectScreen.tsx +1004 -0
  286. package/src/components/RightPanel.tsx +166 -0
  287. package/src/components/RootActivateDialog.tsx +105 -0
  288. package/src/components/SaveDialog.tsx +197 -0
  289. package/src/components/SaveStatus.tsx +69 -0
  290. package/src/components/StatsOverlay.tsx +35 -0
  291. package/src/components/ToolHost.tsx +80 -0
  292. package/src/components/Toolbar.tsx +307 -0
  293. package/src/components/ViewportOverlay.tsx +234 -0
  294. package/src/components/ViewportPanel.tsx +369 -0
  295. package/src/components/WorldContextMenu.tsx +257 -0
  296. package/src/components/WorldSelectionOverlay.tsx +2003 -0
  297. package/src/components/WorldTextEditor.tsx +86 -0
  298. package/src/components/asset-viewers/AssetViewer.tsx +38 -0
  299. package/src/components/asset-viewers/AudioViewer.tsx +149 -0
  300. package/src/components/asset-viewers/GenericJsonViewer.tsx +77 -0
  301. package/src/components/asset-viewers/ImageViewer.tsx +65 -0
  302. package/src/components/asset-viewers/InputMapViewer.tsx +206 -0
  303. package/src/components/asset-viewers/ModelViewer.tsx +180 -0
  304. package/src/components/asset-viewers/OnlineAssetDetail.tsx +236 -0
  305. package/src/components/data-csv.ts +301 -0
  306. package/src/components/entity-name-commit.ts +18 -0
  307. package/src/components/inspector-property-grouping.ts +65 -0
  308. package/src/components/inspector-widgets/AlignmentGrid.tsx +188 -0
  309. package/src/components/inspector-widgets/BorderEditor.tsx +305 -0
  310. package/src/components/inspector-widgets/ColorPicker.tsx +548 -0
  311. package/src/components/inspector-widgets/FilterEditor.tsx +108 -0
  312. package/src/components/inspector-widgets/FontPicker.tsx +196 -0
  313. package/src/components/inspector-widgets/GradientEditor.tsx +277 -0
  314. package/src/components/inspector-widgets/ScrubbableInput.tsx +152 -0
  315. package/src/components/inspector-widgets/ShadowEditor.tsx +332 -0
  316. package/src/components/inspector-widgets/color-utils.ts +202 -0
  317. package/src/components/inspector-widgets/gallery-main.tsx +167 -0
  318. package/src/components/inspector-widgets/index.ts +22 -0
  319. package/src/components/inspector-widgets/shared.tsx +135 -0
  320. package/src/components/inspectors/AnimationSection.tsx +143 -0
  321. package/src/components/inspectors/AudioSection.tsx +215 -0
  322. package/src/components/inspectors/BoneAttachmentSection.tsx +82 -0
  323. package/src/components/inspectors/CameraSection.tsx +105 -0
  324. package/src/components/inspectors/ComponentsSection.tsx +358 -0
  325. package/src/components/inspectors/JointsSection.tsx +255 -0
  326. package/src/components/inspectors/LightSection.tsx +116 -0
  327. package/src/components/inspectors/MaterialSection.tsx +1189 -0
  328. package/src/components/inspectors/MeshSection.tsx +99 -0
  329. package/src/components/inspectors/NavigationSection.tsx +58 -0
  330. package/src/components/inspectors/ParticleSection.tsx +681 -0
  331. package/src/components/inspectors/PhysicsSection.tsx +326 -0
  332. package/src/components/inspectors/PostProcessingSection.tsx +1290 -0
  333. package/src/components/inspectors/RenderingSection.tsx +109 -0
  334. package/src/components/inspectors/ShadowSection.tsx +84 -0
  335. package/src/components/inspectors/SplineSection.tsx +191 -0
  336. package/src/components/inspectors/TransformSection.tsx +191 -0
  337. package/src/components/inspectors/json-schema-fields.ts +281 -0
  338. package/src/components/inspectors/multi-edit-utils.ts +49 -0
  339. package/src/components/inspectors/zod-fields.ts +184 -0
  340. package/src/components/primitives/ColorInput.tsx +109 -0
  341. package/src/components/primitives/JsonInput.tsx +98 -0
  342. package/src/components/primitives/NumberInput.tsx +164 -0
  343. package/src/components/primitives/Panel.tsx +68 -0
  344. package/src/components/primitives/SectionHeader.tsx +45 -0
  345. package/src/components/primitives/Tooltip.tsx +82 -0
  346. package/src/components/primitives/Vec3Input.tsx +62 -0
  347. package/src/components/world-overlay-gestures.ts +1438 -0
  348. package/src/doctor/data-checks.ts +285 -0
  349. package/src/doctor/report.ts +386 -0
  350. package/src/editor-api.ts +700 -0
  351. package/src/editor-console.ts +194 -0
  352. package/src/editor-hotkeys.ts +441 -0
  353. package/src/editor-layers.ts +2 -0
  354. package/src/editor-mode.ts +28 -0
  355. package/src/editor-store.ts +2225 -0
  356. package/src/editor-viewport.ts +1924 -0
  357. package/src/entity-factory.ts +221 -0
  358. package/src/game-globals-prelude.ts +27 -0
  359. package/src/gated-globals.ts +131 -0
  360. package/src/generated/setup-by-example.generated.ts +53 -0
  361. package/src/gizmo-registry.ts +608 -0
  362. package/src/handle-system.ts +221 -0
  363. package/src/hierarchy-menu-registry.ts +70 -0
  364. package/src/hierarchy-rows.ts +73 -0
  365. package/src/hosted-example.ts +160 -0
  366. package/src/hotkeys.ts +142 -0
  367. package/src/ingest/discovery-react.ts +132 -0
  368. package/src/ingest/discovery.ts +205 -0
  369. package/src/ingest/discovery2d.ts +204 -0
  370. package/src/ingest/esm-entry-resolution.ts +102 -0
  371. package/src/ingest/games/bloom-composer/game.js +99 -0
  372. package/src/ingest/games/bloom-composer/vgai.game.json +21 -0
  373. package/src/ingest/games/embed-bundle/embed.html +10 -0
  374. package/src/ingest/games/embed-bundle/vgai.game.json +21 -0
  375. package/src/ingest/games/games-fps/assets/collision-world.glb +0 -0
  376. package/src/ingest/games/games-fps/game.js +479 -0
  377. package/src/ingest/games/games-fps/vgai.game.json +24 -0
  378. package/src/ingest/games/iframe-reachable/game-source.js +58 -0
  379. package/src/ingest/games/iframe-reachable/vgai.game.json +21 -0
  380. package/src/ingest/games/interactive-cubes/game.js +139 -0
  381. package/src/ingest/games/interactive-cubes/vgai.game.json +21 -0
  382. package/src/ingest/games/mismatched-three/fake-three.js +38 -0
  383. package/src/ingest/games/mismatched-three/game.js +10 -0
  384. package/src/ingest/games/mismatched-three/vgai.game.json +22 -0
  385. package/src/ingest/games/own-three-bundled/game.js +43 -0
  386. package/src/ingest/games/own-three-bundled/vgai.game.json +21 -0
  387. package/src/ingest/games/pointerlock-maze/game.js +288 -0
  388. package/src/ingest/games/pointerlock-maze/vgai.game.json +22 -0
  389. package/src/ingest/games-2d/_fixtures/first-party-scene.scn2d.json +124 -0
  390. package/src/ingest/games-2d/bubbo-bubbo/vgai.game.json +25 -0
  391. package/src/ingest/games-2d/bunnymark/game.ts +88 -0
  392. package/src/ingest/games-2d/bunnymark/vgai.game.json +21 -0
  393. package/src/ingest/games-2d/flappy/game.ts +148 -0
  394. package/src/ingest/games-2d/flappy/vgai.game.json +21 -0
  395. package/src/ingest/games-2d/flappy-pixi/vgai.game.json +25 -0
  396. package/src/ingest/games-2d/puzzling-potions/vgai.game.json +25 -0
  397. package/src/ingest/games-2d/tilemap-camera/game.ts +115 -0
  398. package/src/ingest/games-2d/tilemap-camera/vgai.game.json +21 -0
  399. package/src/ingest/games-react/react-rpg/entry.tsx +185 -0
  400. package/src/ingest/games-react/react-rpg/shims.d.ts +26 -0
  401. package/src/ingest/games-react/react-rpg/src/ui/game-state.tsx +129 -0
  402. package/src/ingest/games-react/react-rpg/vgai.game.json +21 -0
  403. package/src/ingest/host-namespace-registry.ts +196 -0
  404. package/src/ingest/types.ts +127 -0
  405. package/src/ingest-hierarchy-rows.ts +207 -0
  406. package/src/ingest-mode.ts +2092 -0
  407. package/src/ingest-siblings.ts +466 -0
  408. package/src/initial-scene.ts +194 -0
  409. package/src/inspector-section-registry.ts +117 -0
  410. package/src/interactive-edit-scope.ts +34 -0
  411. package/src/main.tsx +23 -0
  412. package/src/manifest-project.ts +43 -0
  413. package/src/model-thumbnail.ts +156 -0
  414. package/src/module-mode.ts +513 -0
  415. package/src/navmesh-handler.ts +94 -0
  416. package/src/packaged-runtime.ts +49 -0
  417. package/src/play-mode.ts +1148 -0
  418. package/src/playground/main.ts +206 -0
  419. package/src/project-manager.ts +173 -0
  420. package/src/scene-diff.ts +112 -0
  421. package/src/scene-serializer.ts +144 -0
  422. package/src/scene-sync.ts +587 -0
  423. package/src/scene-ui-mode/active-scene-ui.ts +58 -0
  424. package/src/scene-ui-mode/scene-ui-palette-panel.tsx +152 -0
  425. package/src/scene-ui-mode/scene-ui-timeline-tab.tsx +29 -0
  426. package/src/scene-ui-mode/ui-prefab-dialog-host.tsx +74 -0
  427. package/src/scene-ui-mode/ui-prefab-hierarchy-menu.ts +49 -0
  428. package/src/scene-ui-mode/ui-prefab-io.ts +76 -0
  429. package/src/script-loader.ts +143 -0
  430. package/src/storage/fsa-storage.ts +55 -0
  431. package/src/storage/handle-storage.ts +150 -0
  432. package/src/storage/handle-store.ts +116 -0
  433. package/src/storage/http-storage.ts +137 -0
  434. package/src/storage/index.ts +147 -0
  435. package/src/storage/mem-storage.ts +135 -0
  436. package/src/storage/opfs-storage.ts +25 -0
  437. package/src/storage/paths.ts +26 -0
  438. package/src/storage/seed.ts +106 -0
  439. package/src/storage/types.ts +110 -0
  440. package/src/tool-loader.ts +291 -0
  441. package/src/ui-editor/inspector.tsx +563 -0
  442. package/src/ui-editor/node-ops.ts +266 -0
  443. package/src/ui-editor/overlay.tsx +380 -0
  444. package/src/ui-editor/palette.tsx +114 -0
  445. package/src/ui-editor/react-store.ts +78 -0
  446. package/src/ui-editor/timeline-panel.tsx +443 -0
  447. package/src/ui-editor/ui-edit-store.ts +552 -0
  448. package/src/ui-editor/ui-prefab.ts +95 -0
  449. package/src/ui-source/inspect.ts +544 -0
  450. package/src/ui-source/oid-transform.ts +133 -0
  451. package/src/ui-source/source-write-backend.ts +203 -0
  452. package/src/ui-source/tailwind-map.ts +174 -0
  453. package/src/ui-source/writer.ts +1175 -0
  454. package/src/widgets/index.ts +73 -0
  455. package/template/.claude/skills/editor/SKILL.md +252 -0
  456. package/template/CLAUDE.md +512 -0
  457. package/template/LICENSE +30 -0
  458. package/template/emit-schemas.ts +42 -0
  459. package/template/index.html +17 -0
  460. package/template/package.json +53 -0
  461. package/template/project.json +9 -0
  462. package/template/public/audio/ambient-arena.wav +0 -0
  463. package/template/public/audio/ambient-music.wav +0 -0
  464. package/template/public/audio/ambient-nature.wav +0 -0
  465. package/template/public/audio/ambient-wind.wav +0 -0
  466. package/template/public/inputmaps/default.inputmap.json +41 -0
  467. package/template/public/jsm/libs/draco/gltf/draco_decoder.js +33 -0
  468. package/template/public/jsm/libs/draco/gltf/draco_decoder.wasm +0 -0
  469. package/template/public/jsm/libs/draco/gltf/draco_encoder.js +33 -0
  470. package/template/public/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -0
  471. package/template/public/scenes/default.vscn.json +43 -0
  472. package/template/public/scenes/untitled.vscn.json +29 -0
  473. package/template/public/textures/waternormals.jpg +0 -0
  474. package/template/server/colyseus-setup.ts +85 -0
  475. package/template/server/main.ts +34 -0
  476. package/template/server/rooms/arena-room.ts +420 -0
  477. package/template/server/rooms/game-room.ts +162 -0
  478. package/template/server/rooms.ts +15 -0
  479. package/template/server/tsconfig.json +19 -0
  480. package/template/src/data/README.md +40 -0
  481. package/template/src/data/assets.ts +31 -0
  482. package/template/src/data/tuning.data.json +5 -0
  483. package/template/src/data/tuning.schema.json +21 -0
  484. package/template/src/data/tuning.schema.ts +34 -0
  485. package/template/src/data/tuning.ts +24 -0
  486. package/template/src/main.ts +157 -0
  487. package/template/src/scripts/components/data-spinner.ts +45 -0
  488. package/template/src/scripts/components/scene-camera.ts +40 -0
  489. package/template/src/scripts/main.ts +94 -0
  490. package/template/src/scripts/registry.ts +46 -0
  491. package/template/src/tools/README.md +14 -0
  492. package/template/src/tools/example.tool.tsx +91 -0
  493. package/template/src/tools/spin.tool.tsx +101 -0
  494. package/template/src/ui/Button.tsx +27 -0
  495. package/template/src/ui/DefaultHud.tsx +40 -0
  496. package/template/src/ui/KeyHint.tsx +25 -0
  497. package/template/src/ui/Panel.tsx +52 -0
  498. package/template/src/ui/RebindPanel.tsx +129 -0
  499. package/template/src/ui/Slider.tsx +28 -0
  500. package/template/src/ui/StatusDot.tsx +22 -0
  501. package/template/src/ui/Toggle.tsx +19 -0
  502. package/template/src/ui/game-state.tsx +37 -0
  503. package/template/src/ui/index.ts +7 -0
  504. package/template/src/ui/mount-default-hud.tsx +19 -0
  505. package/template/src/ui/mount-ui.ts +15 -0
  506. package/template/tsconfig.json +36 -0
  507. package/template/validate-asset-content.ts +78 -0
  508. package/template/validate-manifest.ts +55 -0
  509. package/template/validate-scenes.ts +211 -0
  510. package/template/vgai.game.json +21 -0
  511. package/template/vite.config.ts +128 -0
  512. package/vite-plugin-example-assets.ts +60 -0
  513. package/vite-plugin-game-globals.ts +46 -0
  514. package/vite-plugin-game-static.ts +71 -0
  515. package/vite-plugin-project-game-static.ts +84 -0
  516. package/vite-plugin-react-game-static.ts +98 -0
  517. package/vite-plugin-react-world-provider.ts +81 -0
  518. package/vite-plugin-react-world-runtime.ts +76 -0
  519. package/vite-plugin-ui-oid.ts +561 -0
@@ -0,0 +1,1290 @@
1
+ import { DEFAULTS } from '@engine/scene/defaults';
2
+ import type { SceneEnvironment, ScenePostProcessing } from '@engine/scene/scene-types';
3
+ import { useEditorStore } from '../../EditorContext';
4
+ import type { EditorStore } from '../../editor-store';
5
+ import { ColorInput } from '../primitives/ColorInput';
6
+ import { NumberInput } from '../primitives/NumberInput';
7
+ import { SectionHeader } from '../primitives/SectionHeader';
8
+
9
+ const labelStyle: React.CSSProperties = { fontSize: 11, color: '#8c8c8c', marginBottom: 2 };
10
+ const effectLabel: React.CSSProperties = {
11
+ fontSize: 10,
12
+ color: '#8c8c8c',
13
+ fontWeight: 700,
14
+ marginTop: 6,
15
+ };
16
+ const selectStyle: React.CSSProperties = {
17
+ width: '100%',
18
+ background: '#2a2d35',
19
+ color: '#c5c8ce',
20
+ border: '1px solid #3a3d45',
21
+ borderRadius: 3,
22
+ padding: '2px 4px',
23
+ fontSize: 11,
24
+ };
25
+ const textInputStyle: React.CSSProperties = {
26
+ ...selectStyle,
27
+ boxSizing: 'border-box' as const,
28
+ };
29
+
30
+ const d = DEFAULTS.postProcessing;
31
+
32
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
33
+
34
+ function updatePP(
35
+ store: EditorStore,
36
+ env: SceneEnvironment,
37
+ key: keyof ScenePostProcessing,
38
+ partial: Record<string, unknown>,
39
+ ): void {
40
+ const prev = env.postProcessing?.[key];
41
+ store.updateEnvironment({
42
+ postProcessing: { ...env.postProcessing, [key]: { ...prev, ...partial } },
43
+ });
44
+ }
45
+
46
+ function EnabledCheckbox({
47
+ store,
48
+ env,
49
+ effectKey,
50
+ checked,
51
+ }: {
52
+ store: EditorStore;
53
+ env: SceneEnvironment;
54
+ effectKey: keyof ScenePostProcessing;
55
+ checked: boolean;
56
+ }) {
57
+ return (
58
+ <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
59
+ <input
60
+ type="checkbox"
61
+ checked={checked}
62
+ onChange={(e) => updatePP(store, env, effectKey, { enabled: e.target.checked })}
63
+ />
64
+ <span style={{ fontSize: 11, color: '#c5c8ce' }}>Enabled</span>
65
+ </div>
66
+ );
67
+ }
68
+
69
+ function Num({
70
+ store,
71
+ env,
72
+ effectKey,
73
+ field,
74
+ label,
75
+ value,
76
+ step,
77
+ }: {
78
+ store: EditorStore;
79
+ env: SceneEnvironment;
80
+ effectKey: keyof ScenePostProcessing;
81
+ field: string;
82
+ label: string;
83
+ value: number;
84
+ step?: number;
85
+ }) {
86
+ return (
87
+ <div>
88
+ <div style={labelStyle}>{label}</div>
89
+ <NumberInput
90
+ value={value}
91
+ onChange={(v) => updatePP(store, env, effectKey, { [field]: v })}
92
+ step={step ?? 0.1}
93
+ />
94
+ </div>
95
+ );
96
+ }
97
+
98
+ function Check({
99
+ store,
100
+ env,
101
+ effectKey,
102
+ field,
103
+ label,
104
+ checked,
105
+ }: {
106
+ store: EditorStore;
107
+ env: SceneEnvironment;
108
+ effectKey: keyof ScenePostProcessing;
109
+ field: string;
110
+ label: string;
111
+ checked: boolean;
112
+ }) {
113
+ return (
114
+ <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
115
+ <input
116
+ type="checkbox"
117
+ checked={checked}
118
+ onChange={(e) => updatePP(store, env, effectKey, { [field]: e.target.checked })}
119
+ />
120
+ <span style={{ fontSize: 11, color: '#c5c8ce' }}>{label}</span>
121
+ </div>
122
+ );
123
+ }
124
+
125
+ // ─── Main component ───────────────────────────────────────────────────────────
126
+
127
+ export function PostProcessingSection() {
128
+ const store = useEditorStore();
129
+ const env: SceneEnvironment = store.environment ?? {};
130
+ const pp = env.postProcessing;
131
+
132
+ return (
133
+ <SectionHeader label="Post Processing" defaultOpen={false}>
134
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
135
+ {/* ═══════════════════════════════════════════════════════════════
136
+ Lighting
137
+ ═══════════════════════════════════════════════════════════════ */}
138
+ <SectionHeader label="Lighting" defaultOpen={false}>
139
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
140
+ {/* SSAO */}
141
+ <div style={effectLabel}>SSAO</div>
142
+ <EnabledCheckbox
143
+ store={store}
144
+ env={env}
145
+ effectKey="ssao"
146
+ checked={pp?.ssao?.enabled ?? false}
147
+ />
148
+ {pp?.ssao?.enabled && (
149
+ <>
150
+ <Num
151
+ store={store}
152
+ env={env}
153
+ effectKey="ssao"
154
+ field="radius"
155
+ label="Radius"
156
+ value={pp.ssao.radius ?? d.ssao.radius}
157
+ step={0.01}
158
+ />
159
+ <Num
160
+ store={store}
161
+ env={env}
162
+ effectKey="ssao"
163
+ field="intensity"
164
+ label="Intensity"
165
+ value={pp.ssao.intensity ?? d.ssao.intensity}
166
+ />
167
+ <Num
168
+ store={store}
169
+ env={env}
170
+ effectKey="ssao"
171
+ field="bias"
172
+ label="Bias"
173
+ value={pp.ssao.bias ?? d.ssao.bias}
174
+ step={0.005}
175
+ />
176
+ <Num
177
+ store={store}
178
+ env={env}
179
+ effectKey="ssao"
180
+ field="samples"
181
+ label="Samples"
182
+ value={pp.ssao.samples ?? d.ssao.samples}
183
+ step={1}
184
+ />
185
+ <Num
186
+ store={store}
187
+ env={env}
188
+ effectKey="ssao"
189
+ field="rings"
190
+ label="Rings"
191
+ value={pp.ssao.rings ?? d.ssao.rings}
192
+ step={1}
193
+ />
194
+ <Num
195
+ store={store}
196
+ env={env}
197
+ effectKey="ssao"
198
+ field="fade"
199
+ label="Fade"
200
+ value={pp.ssao.fade ?? d.ssao.fade}
201
+ step={0.01}
202
+ />
203
+ <div>
204
+ <div style={labelStyle}>Color</div>
205
+ <ColorInput
206
+ value={pp.ssao.color ?? '#000000'}
207
+ onChange={(v) => updatePP(store, env, 'ssao', { color: v })}
208
+ />
209
+ </div>
210
+ </>
211
+ )}
212
+
213
+ {/* N8AO */}
214
+ <div style={effectLabel}>N8AO</div>
215
+ <EnabledCheckbox
216
+ store={store}
217
+ env={env}
218
+ effectKey="n8ao"
219
+ checked={pp?.n8ao?.enabled ?? false}
220
+ />
221
+ {pp?.n8ao?.enabled && (
222
+ <>
223
+ <Num
224
+ store={store}
225
+ env={env}
226
+ effectKey="n8ao"
227
+ field="aoSamples"
228
+ label="AO Samples"
229
+ value={pp.n8ao.aoSamples ?? d.n8ao.aoSamples}
230
+ step={1}
231
+ />
232
+ <Num
233
+ store={store}
234
+ env={env}
235
+ effectKey="n8ao"
236
+ field="aoRadius"
237
+ label="AO Radius"
238
+ value={pp.n8ao.aoRadius ?? d.n8ao.aoRadius}
239
+ step={0.5}
240
+ />
241
+ <Num
242
+ store={store}
243
+ env={env}
244
+ effectKey="n8ao"
245
+ field="intensity"
246
+ label="Intensity"
247
+ value={pp.n8ao.intensity ?? d.n8ao.intensity}
248
+ step={0.5}
249
+ />
250
+ <Num
251
+ store={store}
252
+ env={env}
253
+ effectKey="n8ao"
254
+ field="denoiseSamples"
255
+ label="Denoise Samples"
256
+ value={pp.n8ao.denoiseSamples ?? d.n8ao.denoiseSamples}
257
+ step={1}
258
+ />
259
+ <Num
260
+ store={store}
261
+ env={env}
262
+ effectKey="n8ao"
263
+ field="denoiseRadius"
264
+ label="Denoise Radius"
265
+ value={pp.n8ao.denoiseRadius ?? d.n8ao.denoiseRadius}
266
+ step={1}
267
+ />
268
+ <Num
269
+ store={store}
270
+ env={env}
271
+ effectKey="n8ao"
272
+ field="distanceFalloff"
273
+ label="Distance Falloff"
274
+ value={pp.n8ao.distanceFalloff ?? d.n8ao.distanceFalloff}
275
+ />
276
+ <Check
277
+ store={store}
278
+ env={env}
279
+ effectKey="n8ao"
280
+ field="screenSpaceRadius"
281
+ label="Screen-Space Radius"
282
+ checked={pp.n8ao.screenSpaceRadius ?? false}
283
+ />
284
+ <Check
285
+ store={store}
286
+ env={env}
287
+ effectKey="n8ao"
288
+ field="halfRes"
289
+ label="Half Resolution"
290
+ checked={pp.n8ao.halfRes ?? false}
291
+ />
292
+ <div>
293
+ <div style={labelStyle}>Color</div>
294
+ <ColorInput
295
+ value={pp.n8ao.color ?? '#000000'}
296
+ onChange={(v) => updatePP(store, env, 'n8ao', { color: v })}
297
+ />
298
+ </div>
299
+ </>
300
+ )}
301
+
302
+ {/* SSR */}
303
+ <div style={effectLabel}>Screen-Space Reflections</div>
304
+ <EnabledCheckbox
305
+ store={store}
306
+ env={env}
307
+ effectKey="ssr"
308
+ checked={pp?.ssr?.enabled ?? false}
309
+ />
310
+ {pp?.ssr?.enabled && (
311
+ <>
312
+ <Num
313
+ store={store}
314
+ env={env}
315
+ effectKey="ssr"
316
+ field="intensity"
317
+ label="Intensity"
318
+ value={pp.ssr.intensity ?? d.ssr.intensity}
319
+ />
320
+ <Num
321
+ store={store}
322
+ env={env}
323
+ effectKey="ssr"
324
+ field="exponent"
325
+ label="Exponent"
326
+ value={pp.ssr.exponent ?? d.ssr.exponent}
327
+ />
328
+ <Num
329
+ store={store}
330
+ env={env}
331
+ effectKey="ssr"
332
+ field="distance"
333
+ label="Distance"
334
+ value={pp.ssr.distance ?? d.ssr.distance}
335
+ step={1}
336
+ />
337
+ <Num
338
+ store={store}
339
+ env={env}
340
+ effectKey="ssr"
341
+ field="thickness"
342
+ label="Thickness"
343
+ value={pp.ssr.thickness ?? d.ssr.thickness}
344
+ step={1}
345
+ />
346
+ <Num
347
+ store={store}
348
+ env={env}
349
+ effectKey="ssr"
350
+ field="maxRoughness"
351
+ label="Max Roughness"
352
+ value={pp.ssr.maxRoughness ?? d.ssr.maxRoughness}
353
+ step={0.05}
354
+ />
355
+ </>
356
+ )}
357
+
358
+ {/* SSGI */}
359
+ <div style={effectLabel}>Screen-Space Global Illumination</div>
360
+ <EnabledCheckbox
361
+ store={store}
362
+ env={env}
363
+ effectKey="ssgi"
364
+ checked={pp?.ssgi?.enabled ?? false}
365
+ />
366
+ {pp?.ssgi?.enabled && (
367
+ <>
368
+ <Num
369
+ store={store}
370
+ env={env}
371
+ effectKey="ssgi"
372
+ field="intensity"
373
+ label="Intensity"
374
+ value={pp.ssgi.intensity ?? d.ssgi.intensity}
375
+ />
376
+ <Num
377
+ store={store}
378
+ env={env}
379
+ effectKey="ssgi"
380
+ field="distance"
381
+ label="Distance"
382
+ value={pp.ssgi.distance ?? d.ssgi.distance}
383
+ step={1}
384
+ />
385
+ <Num
386
+ store={store}
387
+ env={env}
388
+ effectKey="ssgi"
389
+ field="thickness"
390
+ label="Thickness"
391
+ value={pp.ssgi.thickness ?? d.ssgi.thickness}
392
+ step={1}
393
+ />
394
+ <Num
395
+ store={store}
396
+ env={env}
397
+ effectKey="ssgi"
398
+ field="maxRoughness"
399
+ label="Max Roughness"
400
+ value={pp.ssgi.maxRoughness ?? d.ssgi.maxRoughness}
401
+ step={0.05}
402
+ />
403
+ </>
404
+ )}
405
+
406
+ {/* God Rays */}
407
+ <div style={effectLabel}>God Rays</div>
408
+ <EnabledCheckbox
409
+ store={store}
410
+ env={env}
411
+ effectKey="godRays"
412
+ checked={pp?.godRays?.enabled ?? false}
413
+ />
414
+ {pp?.godRays?.enabled && (
415
+ <>
416
+ <div>
417
+ <div style={labelStyle}>Source Entity ID</div>
418
+ <input
419
+ type="text"
420
+ value={pp.godRays.sourceEntity ?? ''}
421
+ onChange={(e) =>
422
+ updatePP(store, env, 'godRays', { sourceEntity: e.target.value })
423
+ }
424
+ placeholder="Entity ID of light source mesh"
425
+ style={textInputStyle}
426
+ />
427
+ </div>
428
+ <Num
429
+ store={store}
430
+ env={env}
431
+ effectKey="godRays"
432
+ field="density"
433
+ label="Density"
434
+ value={pp.godRays.density ?? d.godRays.density}
435
+ step={0.01}
436
+ />
437
+ <Num
438
+ store={store}
439
+ env={env}
440
+ effectKey="godRays"
441
+ field="decay"
442
+ label="Decay"
443
+ value={pp.godRays.decay ?? d.godRays.decay}
444
+ step={0.01}
445
+ />
446
+ <Num
447
+ store={store}
448
+ env={env}
449
+ effectKey="godRays"
450
+ field="weight"
451
+ label="Weight"
452
+ value={pp.godRays.weight ?? d.godRays.weight}
453
+ step={0.05}
454
+ />
455
+ <Num
456
+ store={store}
457
+ env={env}
458
+ effectKey="godRays"
459
+ field="exposure"
460
+ label="Exposure"
461
+ value={pp.godRays.exposure ?? d.godRays.exposure}
462
+ step={0.05}
463
+ />
464
+ <Num
465
+ store={store}
466
+ env={env}
467
+ effectKey="godRays"
468
+ field="samples"
469
+ label="Samples"
470
+ value={pp.godRays.samples ?? d.godRays.samples}
471
+ step={1}
472
+ />
473
+ </>
474
+ )}
475
+ </div>
476
+ </SectionHeader>
477
+
478
+ {/* ═══════════════════════════════════════════════════════════════
479
+ Camera
480
+ ═══════════════════════════════════════════════════════════════ */}
481
+ <SectionHeader label="Camera" defaultOpen={false}>
482
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
483
+ {/* Bloom */}
484
+ <div style={effectLabel}>Bloom</div>
485
+ <EnabledCheckbox
486
+ store={store}
487
+ env={env}
488
+ effectKey="bloom"
489
+ checked={pp?.bloom?.enabled ?? false}
490
+ />
491
+ {pp?.bloom?.enabled && (
492
+ <>
493
+ <Num
494
+ store={store}
495
+ env={env}
496
+ effectKey="bloom"
497
+ field="intensity"
498
+ label="Intensity"
499
+ value={pp.bloom.intensity ?? d.bloom.intensity}
500
+ />
501
+ <Num
502
+ store={store}
503
+ env={env}
504
+ effectKey="bloom"
505
+ field="luminanceThreshold"
506
+ label="Luminance Threshold"
507
+ value={pp.bloom.luminanceThreshold ?? d.bloom.luminanceThreshold}
508
+ step={0.05}
509
+ />
510
+ <Num
511
+ store={store}
512
+ env={env}
513
+ effectKey="bloom"
514
+ field="luminanceSmoothing"
515
+ label="Luminance Smoothing"
516
+ value={pp.bloom.luminanceSmoothing ?? d.bloom.luminanceSmoothing}
517
+ step={0.005}
518
+ />
519
+ </>
520
+ )}
521
+
522
+ {/* Depth of Field */}
523
+ <div style={effectLabel}>Depth of Field</div>
524
+ <EnabledCheckbox
525
+ store={store}
526
+ env={env}
527
+ effectKey="depthOfField"
528
+ checked={pp?.depthOfField?.enabled ?? false}
529
+ />
530
+ {pp?.depthOfField?.enabled && (
531
+ <>
532
+ <Num
533
+ store={store}
534
+ env={env}
535
+ effectKey="depthOfField"
536
+ field="worldFocusDistance"
537
+ label="Focus Distance"
538
+ value={pp.depthOfField.worldFocusDistance ?? d.depthOfField.worldFocusDistance}
539
+ step={0.5}
540
+ />
541
+ <Num
542
+ store={store}
543
+ env={env}
544
+ effectKey="depthOfField"
545
+ field="worldFocusRange"
546
+ label="Focus Range"
547
+ value={pp.depthOfField.worldFocusRange ?? d.depthOfField.worldFocusRange}
548
+ step={0.5}
549
+ />
550
+ <Num
551
+ store={store}
552
+ env={env}
553
+ effectKey="depthOfField"
554
+ field="bokehScale"
555
+ label="Bokeh Scale"
556
+ value={pp.depthOfField.bokehScale ?? d.depthOfField.bokehScale}
557
+ step={0.5}
558
+ />
559
+ <Num
560
+ store={store}
561
+ env={env}
562
+ effectKey="depthOfField"
563
+ field="focalLength"
564
+ label="Focal Length"
565
+ value={pp.depthOfField.focalLength ?? d.depthOfField.focalLength}
566
+ step={0.01}
567
+ />
568
+ </>
569
+ )}
570
+
571
+ {/* Tilt Shift */}
572
+ <div style={effectLabel}>Tilt Shift</div>
573
+ <EnabledCheckbox
574
+ store={store}
575
+ env={env}
576
+ effectKey="tiltShift"
577
+ checked={pp?.tiltShift?.enabled ?? false}
578
+ />
579
+ {pp?.tiltShift?.enabled && (
580
+ <>
581
+ <Num
582
+ store={store}
583
+ env={env}
584
+ effectKey="tiltShift"
585
+ field="offset"
586
+ label="Offset"
587
+ value={pp.tiltShift.offset ?? d.tiltShift.offset}
588
+ step={0.05}
589
+ />
590
+ <Num
591
+ store={store}
592
+ env={env}
593
+ effectKey="tiltShift"
594
+ field="rotation"
595
+ label="Rotation"
596
+ value={pp.tiltShift.rotation ?? d.tiltShift.rotation}
597
+ step={0.05}
598
+ />
599
+ <Num
600
+ store={store}
601
+ env={env}
602
+ effectKey="tiltShift"
603
+ field="focusArea"
604
+ label="Focus Area"
605
+ value={pp.tiltShift.focusArea ?? d.tiltShift.focusArea}
606
+ step={0.05}
607
+ />
608
+ <Num
609
+ store={store}
610
+ env={env}
611
+ effectKey="tiltShift"
612
+ field="feather"
613
+ label="Feather"
614
+ value={pp.tiltShift.feather ?? d.tiltShift.feather}
615
+ step={0.05}
616
+ />
617
+ </>
618
+ )}
619
+
620
+ {/* Chromatic Aberration */}
621
+ <div style={effectLabel}>Chromatic Aberration</div>
622
+ <EnabledCheckbox
623
+ store={store}
624
+ env={env}
625
+ effectKey="chromaticAberration"
626
+ checked={pp?.chromaticAberration?.enabled ?? false}
627
+ />
628
+ {pp?.chromaticAberration?.enabled && (
629
+ <>
630
+ <Num
631
+ store={store}
632
+ env={env}
633
+ effectKey="chromaticAberration"
634
+ field="offsetX"
635
+ label="Offset X"
636
+ value={pp.chromaticAberration.offsetX ?? d.chromaticAberration.offsetX}
637
+ step={0.001}
638
+ />
639
+ <Num
640
+ store={store}
641
+ env={env}
642
+ effectKey="chromaticAberration"
643
+ field="offsetY"
644
+ label="Offset Y"
645
+ value={pp.chromaticAberration.offsetY ?? d.chromaticAberration.offsetY}
646
+ step={0.001}
647
+ />
648
+ <Check
649
+ store={store}
650
+ env={env}
651
+ effectKey="chromaticAberration"
652
+ field="radialModulation"
653
+ label="Radial Modulation"
654
+ checked={pp.chromaticAberration.radialModulation ?? false}
655
+ />
656
+ <Num
657
+ store={store}
658
+ env={env}
659
+ effectKey="chromaticAberration"
660
+ field="modulationOffset"
661
+ label="Modulation Offset"
662
+ value={
663
+ pp.chromaticAberration.modulationOffset ??
664
+ d.chromaticAberration.modulationOffset
665
+ }
666
+ step={0.05}
667
+ />
668
+ </>
669
+ )}
670
+
671
+ {/* Lens Distortion */}
672
+ <div style={effectLabel}>Lens Distortion</div>
673
+ <EnabledCheckbox
674
+ store={store}
675
+ env={env}
676
+ effectKey="lensDistortion"
677
+ checked={pp?.lensDistortion?.enabled ?? false}
678
+ />
679
+ {pp?.lensDistortion?.enabled && (
680
+ <>
681
+ <Num
682
+ store={store}
683
+ env={env}
684
+ effectKey="lensDistortion"
685
+ field="distortionX"
686
+ label="Distortion X"
687
+ value={pp.lensDistortion.distortionX ?? d.lensDistortion.distortionX}
688
+ step={0.05}
689
+ />
690
+ <Num
691
+ store={store}
692
+ env={env}
693
+ effectKey="lensDistortion"
694
+ field="distortionY"
695
+ label="Distortion Y"
696
+ value={pp.lensDistortion.distortionY ?? d.lensDistortion.distortionY}
697
+ step={0.05}
698
+ />
699
+ <Num
700
+ store={store}
701
+ env={env}
702
+ effectKey="lensDistortion"
703
+ field="focalLengthX"
704
+ label="Focal Length X"
705
+ value={pp.lensDistortion.focalLengthX ?? d.lensDistortion.focalLengthX}
706
+ step={0.05}
707
+ />
708
+ <Num
709
+ store={store}
710
+ env={env}
711
+ effectKey="lensDistortion"
712
+ field="focalLengthY"
713
+ label="Focal Length Y"
714
+ value={pp.lensDistortion.focalLengthY ?? d.lensDistortion.focalLengthY}
715
+ step={0.05}
716
+ />
717
+ <Num
718
+ store={store}
719
+ env={env}
720
+ effectKey="lensDistortion"
721
+ field="skew"
722
+ label="Skew"
723
+ value={pp.lensDistortion.skew ?? d.lensDistortion.skew}
724
+ step={0.01}
725
+ />
726
+ </>
727
+ )}
728
+
729
+ {/* Motion Blur */}
730
+ <div style={effectLabel}>Motion Blur</div>
731
+ <EnabledCheckbox
732
+ store={store}
733
+ env={env}
734
+ effectKey="motionBlur"
735
+ checked={pp?.motionBlur?.enabled ?? false}
736
+ />
737
+ {pp?.motionBlur?.enabled && (
738
+ <>
739
+ <Num
740
+ store={store}
741
+ env={env}
742
+ effectKey="motionBlur"
743
+ field="intensity"
744
+ label="Intensity"
745
+ value={pp.motionBlur.intensity ?? d.motionBlur.intensity}
746
+ />
747
+ <Num
748
+ store={store}
749
+ env={env}
750
+ effectKey="motionBlur"
751
+ field="jitter"
752
+ label="Jitter"
753
+ value={pp.motionBlur.jitter ?? d.motionBlur.jitter}
754
+ />
755
+ <Num
756
+ store={store}
757
+ env={env}
758
+ effectKey="motionBlur"
759
+ field="samples"
760
+ label="Samples"
761
+ value={pp.motionBlur.samples ?? d.motionBlur.samples}
762
+ step={1}
763
+ />
764
+ </>
765
+ )}
766
+ </div>
767
+ </SectionHeader>
768
+
769
+ {/* ═══════════════════════════════════════════════════════════════
770
+ Color
771
+ ═══════════════════════════════════════════════════════════════ */}
772
+ <SectionHeader label="Color" defaultOpen={false}>
773
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
774
+ {/* Brightness / Contrast */}
775
+ <div style={effectLabel}>Brightness / Contrast</div>
776
+ <EnabledCheckbox
777
+ store={store}
778
+ env={env}
779
+ effectKey="brightnessContrast"
780
+ checked={pp?.brightnessContrast?.enabled ?? false}
781
+ />
782
+ {pp?.brightnessContrast?.enabled && (
783
+ <>
784
+ <Num
785
+ store={store}
786
+ env={env}
787
+ effectKey="brightnessContrast"
788
+ field="brightness"
789
+ label="Brightness"
790
+ value={pp.brightnessContrast.brightness ?? d.brightnessContrast.brightness}
791
+ step={0.05}
792
+ />
793
+ <Num
794
+ store={store}
795
+ env={env}
796
+ effectKey="brightnessContrast"
797
+ field="contrast"
798
+ label="Contrast"
799
+ value={pp.brightnessContrast.contrast ?? d.brightnessContrast.contrast}
800
+ step={0.05}
801
+ />
802
+ </>
803
+ )}
804
+
805
+ {/* Hue / Saturation */}
806
+ <div style={effectLabel}>Hue / Saturation</div>
807
+ <EnabledCheckbox
808
+ store={store}
809
+ env={env}
810
+ effectKey="hueSaturation"
811
+ checked={pp?.hueSaturation?.enabled ?? false}
812
+ />
813
+ {pp?.hueSaturation?.enabled && (
814
+ <>
815
+ <Num
816
+ store={store}
817
+ env={env}
818
+ effectKey="hueSaturation"
819
+ field="hue"
820
+ label="Hue"
821
+ value={pp.hueSaturation.hue ?? d.hueSaturation.hue}
822
+ step={0.05}
823
+ />
824
+ <Num
825
+ store={store}
826
+ env={env}
827
+ effectKey="hueSaturation"
828
+ field="saturation"
829
+ label="Saturation"
830
+ value={pp.hueSaturation.saturation ?? d.hueSaturation.saturation}
831
+ step={0.05}
832
+ />
833
+ </>
834
+ )}
835
+
836
+ {/* Sepia */}
837
+ <div style={effectLabel}>Sepia</div>
838
+ <EnabledCheckbox
839
+ store={store}
840
+ env={env}
841
+ effectKey="sepia"
842
+ checked={pp?.sepia?.enabled ?? false}
843
+ />
844
+ {pp?.sepia?.enabled && (
845
+ <Num
846
+ store={store}
847
+ env={env}
848
+ effectKey="sepia"
849
+ field="intensity"
850
+ label="Intensity"
851
+ value={pp.sepia.intensity ?? d.sepia.intensity}
852
+ step={0.05}
853
+ />
854
+ )}
855
+
856
+ {/* Color Depth */}
857
+ <div style={effectLabel}>Color Depth</div>
858
+ <EnabledCheckbox
859
+ store={store}
860
+ env={env}
861
+ effectKey="colorDepth"
862
+ checked={pp?.colorDepth?.enabled ?? false}
863
+ />
864
+ {pp?.colorDepth?.enabled && (
865
+ <Num
866
+ store={store}
867
+ env={env}
868
+ effectKey="colorDepth"
869
+ field="bits"
870
+ label="Bits"
871
+ value={pp.colorDepth.bits ?? d.colorDepth.bits}
872
+ step={1}
873
+ />
874
+ )}
875
+ </div>
876
+ </SectionHeader>
877
+
878
+ {/* ═══════════════════════════════════════════════════════════════
879
+ Stylistic
880
+ ═══════════════════════════════════════════════════════════════ */}
881
+ <SectionHeader label="Stylistic" defaultOpen={false}>
882
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
883
+ {/* Vignette */}
884
+ <div style={effectLabel}>Vignette</div>
885
+ <EnabledCheckbox
886
+ store={store}
887
+ env={env}
888
+ effectKey="vignette"
889
+ checked={pp?.vignette?.enabled ?? false}
890
+ />
891
+ {pp?.vignette?.enabled && (
892
+ <>
893
+ <Num
894
+ store={store}
895
+ env={env}
896
+ effectKey="vignette"
897
+ field="darkness"
898
+ label="Darkness"
899
+ value={pp.vignette.darkness ?? d.vignette.darkness}
900
+ step={0.05}
901
+ />
902
+ <Num
903
+ store={store}
904
+ env={env}
905
+ effectKey="vignette"
906
+ field="offset"
907
+ label="Offset"
908
+ value={pp.vignette.offset ?? d.vignette.offset}
909
+ step={0.05}
910
+ />
911
+ </>
912
+ )}
913
+
914
+ {/* Noise */}
915
+ <div style={effectLabel}>Noise (Film Grain)</div>
916
+ <EnabledCheckbox
917
+ store={store}
918
+ env={env}
919
+ effectKey="noise"
920
+ checked={pp?.noise?.enabled ?? false}
921
+ />
922
+ {pp?.noise?.enabled && (
923
+ <Check
924
+ store={store}
925
+ env={env}
926
+ effectKey="noise"
927
+ field="premultiply"
928
+ label="Premultiply"
929
+ checked={pp.noise.premultiply ?? d.noise.premultiply}
930
+ />
931
+ )}
932
+
933
+ {/* Scanline */}
934
+ <div style={effectLabel}>Scanline</div>
935
+ <EnabledCheckbox
936
+ store={store}
937
+ env={env}
938
+ effectKey="scanline"
939
+ checked={pp?.scanline?.enabled ?? false}
940
+ />
941
+ {pp?.scanline?.enabled && (
942
+ <Num
943
+ store={store}
944
+ env={env}
945
+ effectKey="scanline"
946
+ field="density"
947
+ label="Density"
948
+ value={pp.scanline.density ?? d.scanline.density}
949
+ step={0.05}
950
+ />
951
+ )}
952
+
953
+ {/* Dot Screen */}
954
+ <div style={effectLabel}>Dot Screen</div>
955
+ <EnabledCheckbox
956
+ store={store}
957
+ env={env}
958
+ effectKey="dotScreen"
959
+ checked={pp?.dotScreen?.enabled ?? false}
960
+ />
961
+ {pp?.dotScreen?.enabled && (
962
+ <>
963
+ <Num
964
+ store={store}
965
+ env={env}
966
+ effectKey="dotScreen"
967
+ field="angle"
968
+ label="Angle"
969
+ value={pp.dotScreen.angle ?? d.dotScreen.angle}
970
+ step={0.05}
971
+ />
972
+ <Num
973
+ store={store}
974
+ env={env}
975
+ effectKey="dotScreen"
976
+ field="scale"
977
+ label="Scale"
978
+ value={pp.dotScreen.scale ?? d.dotScreen.scale}
979
+ />
980
+ </>
981
+ )}
982
+
983
+ {/* Grid */}
984
+ <div style={effectLabel}>Grid</div>
985
+ <EnabledCheckbox
986
+ store={store}
987
+ env={env}
988
+ effectKey="grid"
989
+ checked={pp?.grid?.enabled ?? false}
990
+ />
991
+ {pp?.grid?.enabled && (
992
+ <>
993
+ <Num
994
+ store={store}
995
+ env={env}
996
+ effectKey="grid"
997
+ field="scale"
998
+ label="Scale"
999
+ value={pp.grid.scale ?? d.grid.scale}
1000
+ />
1001
+ <Num
1002
+ store={store}
1003
+ env={env}
1004
+ effectKey="grid"
1005
+ field="lineWidth"
1006
+ label="Line Width"
1007
+ value={pp.grid.lineWidth ?? d.grid.lineWidth}
1008
+ step={0.01}
1009
+ />
1010
+ </>
1011
+ )}
1012
+
1013
+ {/* Pixelation */}
1014
+ <div style={effectLabel}>Pixelation</div>
1015
+ <EnabledCheckbox
1016
+ store={store}
1017
+ env={env}
1018
+ effectKey="pixelation"
1019
+ checked={pp?.pixelation?.enabled ?? false}
1020
+ />
1021
+ {pp?.pixelation?.enabled && (
1022
+ <Num
1023
+ store={store}
1024
+ env={env}
1025
+ effectKey="pixelation"
1026
+ field="granularity"
1027
+ label="Granularity"
1028
+ value={pp.pixelation.granularity ?? d.pixelation.granularity}
1029
+ step={1}
1030
+ />
1031
+ )}
1032
+
1033
+ {/* Glitch */}
1034
+ <div style={effectLabel}>Glitch</div>
1035
+ <EnabledCheckbox
1036
+ store={store}
1037
+ env={env}
1038
+ effectKey="glitch"
1039
+ checked={pp?.glitch?.enabled ?? false}
1040
+ />
1041
+ {pp?.glitch?.enabled && (
1042
+ <>
1043
+ <Num
1044
+ store={store}
1045
+ env={env}
1046
+ effectKey="glitch"
1047
+ field="delayX"
1048
+ label="Delay Min"
1049
+ value={pp.glitch.delayX ?? d.glitch.delayX}
1050
+ />
1051
+ <Num
1052
+ store={store}
1053
+ env={env}
1054
+ effectKey="glitch"
1055
+ field="delayY"
1056
+ label="Delay Max"
1057
+ value={pp.glitch.delayY ?? d.glitch.delayY}
1058
+ />
1059
+ <Num
1060
+ store={store}
1061
+ env={env}
1062
+ effectKey="glitch"
1063
+ field="durationX"
1064
+ label="Duration Min"
1065
+ value={pp.glitch.durationX ?? d.glitch.durationX}
1066
+ />
1067
+ <Num
1068
+ store={store}
1069
+ env={env}
1070
+ effectKey="glitch"
1071
+ field="durationY"
1072
+ label="Duration Max"
1073
+ value={pp.glitch.durationY ?? d.glitch.durationY}
1074
+ />
1075
+ <Num
1076
+ store={store}
1077
+ env={env}
1078
+ effectKey="glitch"
1079
+ field="strengthX"
1080
+ label="Strength Min"
1081
+ value={pp.glitch.strengthX ?? d.glitch.strengthX}
1082
+ step={0.05}
1083
+ />
1084
+ <Num
1085
+ store={store}
1086
+ env={env}
1087
+ effectKey="glitch"
1088
+ field="strengthY"
1089
+ label="Strength Max"
1090
+ value={pp.glitch.strengthY ?? d.glitch.strengthY}
1091
+ step={0.05}
1092
+ />
1093
+ <Num
1094
+ store={store}
1095
+ env={env}
1096
+ effectKey="glitch"
1097
+ field="columns"
1098
+ label="Columns"
1099
+ value={pp.glitch.columns ?? d.glitch.columns}
1100
+ step={0.01}
1101
+ />
1102
+ <Num
1103
+ store={store}
1104
+ env={env}
1105
+ effectKey="glitch"
1106
+ field="ratio"
1107
+ label="Ratio"
1108
+ value={pp.glitch.ratio ?? d.glitch.ratio}
1109
+ step={0.05}
1110
+ />
1111
+ </>
1112
+ )}
1113
+
1114
+ {/* Outline */}
1115
+ <div style={effectLabel}>Outline</div>
1116
+ <EnabledCheckbox
1117
+ store={store}
1118
+ env={env}
1119
+ effectKey="outline"
1120
+ checked={pp?.outline?.enabled ?? false}
1121
+ />
1122
+ {pp?.outline?.enabled && (
1123
+ <>
1124
+ <div>
1125
+ <div style={labelStyle}>Tags (comma-separated)</div>
1126
+ <input
1127
+ type="text"
1128
+ value={(pp.outline.tags ?? []).join(', ')}
1129
+ onChange={(e) => {
1130
+ const tags = e.target.value
1131
+ .split(',')
1132
+ .map((t) => t.trim())
1133
+ .filter((t) => t.length > 0);
1134
+ updatePP(store, env, 'outline', { tags });
1135
+ }}
1136
+ placeholder="e.g. highlighted, selected"
1137
+ style={textInputStyle}
1138
+ />
1139
+ </div>
1140
+ <Num
1141
+ store={store}
1142
+ env={env}
1143
+ effectKey="outline"
1144
+ field="edgeStrength"
1145
+ label="Edge Strength"
1146
+ value={pp.outline.edgeStrength ?? d.outline.edgeStrength}
1147
+ step={0.5}
1148
+ />
1149
+ <Num
1150
+ store={store}
1151
+ env={env}
1152
+ effectKey="outline"
1153
+ field="pulseSpeed"
1154
+ label="Pulse Speed"
1155
+ value={pp.outline.pulseSpeed ?? d.outline.pulseSpeed}
1156
+ />
1157
+ <div>
1158
+ <div style={labelStyle}>Visible Edge Color</div>
1159
+ <ColorInput
1160
+ value={pp.outline.visibleEdgeColor ?? d.outline.visibleEdgeColor}
1161
+ onChange={(v) => updatePP(store, env, 'outline', { visibleEdgeColor: v })}
1162
+ />
1163
+ </div>
1164
+ <div>
1165
+ <div style={labelStyle}>Hidden Edge Color</div>
1166
+ <ColorInput
1167
+ value={pp.outline.hiddenEdgeColor ?? d.outline.hiddenEdgeColor}
1168
+ onChange={(v) => updatePP(store, env, 'outline', { hiddenEdgeColor: v })}
1169
+ />
1170
+ </div>
1171
+ <Check
1172
+ store={store}
1173
+ env={env}
1174
+ effectKey="outline"
1175
+ field="xRay"
1176
+ label="X-Ray"
1177
+ checked={pp.outline.xRay ?? false}
1178
+ />
1179
+ </>
1180
+ )}
1181
+
1182
+ {/* Shock Wave */}
1183
+ <div style={effectLabel}>Shock Wave</div>
1184
+ <EnabledCheckbox
1185
+ store={store}
1186
+ env={env}
1187
+ effectKey="shockWave"
1188
+ checked={pp?.shockWave?.enabled ?? false}
1189
+ />
1190
+ {pp?.shockWave?.enabled && (
1191
+ <>
1192
+ <Num
1193
+ store={store}
1194
+ env={env}
1195
+ effectKey="shockWave"
1196
+ field="speed"
1197
+ label="Speed"
1198
+ value={pp.shockWave.speed ?? d.shockWave.speed}
1199
+ />
1200
+ <Num
1201
+ store={store}
1202
+ env={env}
1203
+ effectKey="shockWave"
1204
+ field="maxRadius"
1205
+ label="Max Radius"
1206
+ value={pp.shockWave.maxRadius ?? d.shockWave.maxRadius}
1207
+ />
1208
+ <Num
1209
+ store={store}
1210
+ env={env}
1211
+ effectKey="shockWave"
1212
+ field="waveSize"
1213
+ label="Wave Size"
1214
+ value={pp.shockWave.waveSize ?? d.shockWave.waveSize}
1215
+ step={0.01}
1216
+ />
1217
+ <Num
1218
+ store={store}
1219
+ env={env}
1220
+ effectKey="shockWave"
1221
+ field="amplitude"
1222
+ label="Amplitude"
1223
+ value={pp.shockWave.amplitude ?? d.shockWave.amplitude}
1224
+ step={0.01}
1225
+ />
1226
+ <Num
1227
+ store={store}
1228
+ env={env}
1229
+ effectKey="shockWave"
1230
+ field="positionX"
1231
+ label="Position X"
1232
+ value={pp.shockWave.positionX ?? 0}
1233
+ step={0.5}
1234
+ />
1235
+ <Num
1236
+ store={store}
1237
+ env={env}
1238
+ effectKey="shockWave"
1239
+ field="positionY"
1240
+ label="Position Y"
1241
+ value={pp.shockWave.positionY ?? 0}
1242
+ step={0.5}
1243
+ />
1244
+ <Num
1245
+ store={store}
1246
+ env={env}
1247
+ effectKey="shockWave"
1248
+ field="positionZ"
1249
+ label="Position Z"
1250
+ value={pp.shockWave.positionZ ?? 0}
1251
+ step={0.5}
1252
+ />
1253
+ </>
1254
+ )}
1255
+ </div>
1256
+ </SectionHeader>
1257
+
1258
+ {/* ═══════════════════════════════════════════════════════════════
1259
+ Anti-Aliasing
1260
+ ═══════════════════════════════════════════════════════════════ */}
1261
+ <SectionHeader label="Anti-Aliasing" defaultOpen={false}>
1262
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
1263
+ <div style={effectLabel}>SMAA</div>
1264
+ <EnabledCheckbox
1265
+ store={store}
1266
+ env={env}
1267
+ effectKey="smaa"
1268
+ checked={pp?.smaa?.enabled ?? false}
1269
+ />
1270
+ {pp?.smaa?.enabled && (
1271
+ <div>
1272
+ <div style={labelStyle}>Preset</div>
1273
+ <select
1274
+ value={pp.smaa.preset ?? d.smaa.preset}
1275
+ onChange={(e) => updatePP(store, env, 'smaa', { preset: e.target.value })}
1276
+ style={selectStyle}
1277
+ >
1278
+ <option value="low">Low</option>
1279
+ <option value="medium">Medium</option>
1280
+ <option value="high">High</option>
1281
+ <option value="ultra">Ultra</option>
1282
+ </select>
1283
+ </div>
1284
+ )}
1285
+ </div>
1286
+ </SectionHeader>
1287
+ </div>
1288
+ </SectionHeader>
1289
+ );
1290
+ }