@lampdotdev/lamp 0.0.0-stage → 0.35.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 (464) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +357 -2
  3. package/Resources/Devices/roku.json +410 -0
  4. package/Resources/Devices/xbox-one.json +367 -0
  5. package/Resources/GameKit/NOTICE.md +63 -0
  6. package/Resources/GameKit/apple/LampPage.swift +1646 -0
  7. package/Resources/GameKit/apple/LampPlayer.swift +46 -0
  8. package/Resources/GameKit/apple/LampWebApp.swift +63 -0
  9. package/Resources/GameKit/apple/LampWebGame.swift +87 -0
  10. package/Resources/GameKit/apple/Native.swift +12 -0
  11. package/Resources/GameKit/build.sh +55 -0
  12. package/Resources/GameKit/lamp_game.h +116 -0
  13. package/Resources/GameKit/lamp_host.h +19 -0
  14. package/Resources/GameKit/lamp_kit.cpp +61 -0
  15. package/Resources/GameKit/lamp_sound.cpp +455 -0
  16. package/Resources/GameKit/lamp_xbox.cpp +374 -0
  17. package/Resources/GameKit/libraries/HandmadeMath.h +3940 -0
  18. package/Resources/GameKit/libraries/cgltf.h +7240 -0
  19. package/Resources/GameKit/libraries/dr_mp3.h +5430 -0
  20. package/Resources/GameKit/libraries/dr_wav.h +9209 -0
  21. package/Resources/GameKit/libraries/sokol_debugtext.h +4754 -0
  22. package/Resources/GameKit/libraries/sokol_gfx.h +29558 -0
  23. package/Resources/GameKit/libraries/sokol_gl.h +4538 -0
  24. package/Resources/GameKit/libraries/sokol_log.h +335 -0
  25. package/Resources/GameKit/libraries/sokol_shape.h +1531 -0
  26. package/Resources/GameKit/libraries/stb_image.h +7988 -0
  27. package/Resources/GameKit/libraries/stb_vorbis.c +5584 -0
  28. package/Resources/GameKit/scaffold/Game/game.cpp +142 -0
  29. package/Resources/GameKit/scaffold/Game/scene.glsl +49 -0
  30. package/Resources/GameKit/scaffold-web/Web/game.js +31 -0
  31. package/Resources/GameKit/scaffold-web/Web/index.html +13 -0
  32. package/Resources/GameKit/scaffold-web/Web/making.js +33 -0
  33. package/Resources/GameKit/scaffold-web/Web/world.js +33 -0
  34. package/Resources/GameKit/web/lamp-game.js +3036 -0
  35. package/Resources/GameKit/web/lamp-phaser.js +128 -0
  36. package/Resources/WebHost/App.exe +0 -0
  37. package/Resources/WebHost/Microsoft.Web.WebView2.Core.dll +0 -0
  38. package/Resources/WebHost/WebView2-LICENSE.txt +27 -0
  39. package/Resources/WebHost/lamp_controllers.h +1506 -0
  40. package/Resources/WebHost/lamp_web_host.cpp +1173 -0
  41. package/Resources/WebLibraries/earlier.txt +318 -0
  42. package/Resources/WebLibraries/phaser/LICENSE.md +20 -0
  43. package/Resources/WebLibraries/phaser/NOTICE.md +2 -0
  44. package/Resources/WebLibraries/phaser/phaser.esm.min.js +1 -0
  45. package/Resources/WebLibraries/qrcode/LICENSE +21 -0
  46. package/Resources/WebLibraries/qrcode/NOTICE.md +4 -0
  47. package/Resources/WebLibraries/qrcode/qrcode.js +2297 -0
  48. package/Resources/WebLibraries/rapier/LICENSE +201 -0
  49. package/Resources/WebLibraries/rapier/NOTICE.md +3 -0
  50. package/Resources/WebLibraries/rapier/rapier.js +2 -0
  51. package/Resources/WebLibraries/three/LICENSE +21 -0
  52. package/Resources/WebLibraries/three/NOTICE.md +4 -0
  53. package/Resources/WebLibraries/three/addons/animation/AnimationClipCreator.js +168 -0
  54. package/Resources/WebLibraries/three/addons/animation/CCDIKSolver.js +607 -0
  55. package/Resources/WebLibraries/three/addons/controls/ArcballControls.js +3543 -0
  56. package/Resources/WebLibraries/three/addons/controls/DragControls.js +452 -0
  57. package/Resources/WebLibraries/three/addons/controls/FirstPersonControls.js +512 -0
  58. package/Resources/WebLibraries/three/addons/controls/FlyControls.js +384 -0
  59. package/Resources/WebLibraries/three/addons/controls/MapControls.js +116 -0
  60. package/Resources/WebLibraries/three/addons/controls/OrbitControls.js +1985 -0
  61. package/Resources/WebLibraries/three/addons/controls/PointerLockControls.js +264 -0
  62. package/Resources/WebLibraries/three/addons/controls/TrackballControls.js +1106 -0
  63. package/Resources/WebLibraries/three/addons/controls/TransformControls.js +2003 -0
  64. package/Resources/WebLibraries/three/addons/curves/CurveExtras.js +694 -0
  65. package/Resources/WebLibraries/three/addons/curves/NURBSCurve.js +169 -0
  66. package/Resources/WebLibraries/three/addons/curves/NURBSSurface.js +98 -0
  67. package/Resources/WebLibraries/three/addons/curves/NURBSUtils.js +532 -0
  68. package/Resources/WebLibraries/three/addons/curves/NURBSVolume.js +82 -0
  69. package/Resources/WebLibraries/three/addons/effects/AnaglyphEffect.js +274 -0
  70. package/Resources/WebLibraries/three/addons/effects/AsciiEffect.js +323 -0
  71. package/Resources/WebLibraries/three/addons/effects/OutlineEffect.js +489 -0
  72. package/Resources/WebLibraries/three/addons/effects/ParallaxBarrierEffect.js +155 -0
  73. package/Resources/WebLibraries/three/addons/effects/StereoEffect.js +91 -0
  74. package/Resources/WebLibraries/three/addons/environments/ColorEnvironment.js +59 -0
  75. package/Resources/WebLibraries/three/addons/environments/DebugEnvironment.js +102 -0
  76. package/Resources/WebLibraries/three/addons/environments/RoomEnvironment.js +185 -0
  77. package/Resources/WebLibraries/three/addons/geometries/BoxLineGeometry.js +92 -0
  78. package/Resources/WebLibraries/three/addons/geometries/ConvexGeometry.js +72 -0
  79. package/Resources/WebLibraries/three/addons/geometries/DecalGeometry.js +420 -0
  80. package/Resources/WebLibraries/three/addons/geometries/LoftGeometry.js +355 -0
  81. package/Resources/WebLibraries/three/addons/geometries/ParametricFunctions.js +100 -0
  82. package/Resources/WebLibraries/three/addons/geometries/ParametricGeometry.js +172 -0
  83. package/Resources/WebLibraries/three/addons/geometries/RoundedBoxGeometry.js +216 -0
  84. package/Resources/WebLibraries/three/addons/geometries/TeapotGeometry.js +689 -0
  85. package/Resources/WebLibraries/three/addons/geometries/TextGeometry.js +102 -0
  86. package/Resources/WebLibraries/three/addons/helpers/AnimationPathHelper.js +302 -0
  87. package/Resources/WebLibraries/three/addons/helpers/LightProbeGridHelper.js +166 -0
  88. package/Resources/WebLibraries/three/addons/helpers/LightProbeGridHelperWebGL.js +221 -0
  89. package/Resources/WebLibraries/three/addons/helpers/LightProbeHelper.js +166 -0
  90. package/Resources/WebLibraries/three/addons/helpers/LightProbeHelperGPU.js +102 -0
  91. package/Resources/WebLibraries/three/addons/helpers/OctreeHelper.js +109 -0
  92. package/Resources/WebLibraries/three/addons/helpers/PositionalAudioHelper.js +169 -0
  93. package/Resources/WebLibraries/three/addons/helpers/RapierHelper.js +59 -0
  94. package/Resources/WebLibraries/three/addons/helpers/RectAreaLightHelper.js +118 -0
  95. package/Resources/WebLibraries/three/addons/helpers/TextureHelper.js +265 -0
  96. package/Resources/WebLibraries/three/addons/helpers/TextureHelperGPU.js +214 -0
  97. package/Resources/WebLibraries/three/addons/helpers/VertexNormalsHelper.js +155 -0
  98. package/Resources/WebLibraries/three/addons/helpers/VertexTangentsHelper.js +133 -0
  99. package/Resources/WebLibraries/three/addons/helpers/ViewHelper.js +529 -0
  100. package/Resources/WebLibraries/three/addons/interactive/HTMLMesh.js +617 -0
  101. package/Resources/WebLibraries/three/addons/interactive/InteractiveGroup.js +224 -0
  102. package/Resources/WebLibraries/three/addons/interactive/SelectionBox.js +324 -0
  103. package/Resources/WebLibraries/three/addons/interactive/SelectionHelper.js +150 -0
  104. package/Resources/WebLibraries/three/addons/libs/fflate.module.js +2699 -0
  105. package/Resources/WebLibraries/three/addons/libs/lil-gui.module.min.js +8 -0
  106. package/Resources/WebLibraries/three/addons/libs/meshopt_decoder.module.js +196 -0
  107. package/Resources/WebLibraries/three/addons/libs/potpack.module.js +125 -0
  108. package/Resources/WebLibraries/three/addons/libs/stats.module.js +167 -0
  109. package/Resources/WebLibraries/three/addons/libs/tween.module.js +876 -0
  110. package/Resources/WebLibraries/three/addons/lighting/ClusteredLighting.js +153 -0
  111. package/Resources/WebLibraries/three/addons/lighting/DynamicLighting.js +82 -0
  112. package/Resources/WebLibraries/three/addons/lighting/LightMapper.js +295 -0
  113. package/Resources/WebLibraries/three/addons/lighting/LightProbeGrid.js +923 -0
  114. package/Resources/WebLibraries/three/addons/lighting/LightProbeGridUtils.js +107 -0
  115. package/Resources/WebLibraries/three/addons/lighting/LightProbeGridWebGL.js +846 -0
  116. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIConeTracer.js +243 -0
  117. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIIrradiance.js +43 -0
  118. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGINode.js +617 -0
  119. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGISceneCollector.js +793 -0
  120. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIVolume.js +1440 -0
  121. package/Resources/WebLibraries/three/addons/lights/LightProbeGenerator.js +337 -0
  122. package/Resources/WebLibraries/three/addons/lights/RectAreaLightTexturesLib.js +127 -0
  123. package/Resources/WebLibraries/three/addons/lights/RectAreaLightUniformsLib.js +40 -0
  124. package/Resources/WebLibraries/three/addons/lights/SunLight.js +100 -0
  125. package/Resources/WebLibraries/three/addons/lights/SunLightNode.js +56 -0
  126. package/Resources/WebLibraries/three/addons/lights/SunLightShadow.js +319 -0
  127. package/Resources/WebLibraries/three/addons/lights/SunShadowNode.js +312 -0
  128. package/Resources/WebLibraries/three/addons/lines/Line2.js +56 -0
  129. package/Resources/WebLibraries/three/addons/lines/LineGeometry.js +157 -0
  130. package/Resources/WebLibraries/three/addons/lines/LineMaterial.js +742 -0
  131. package/Resources/WebLibraries/three/addons/lines/LineSegments2.js +434 -0
  132. package/Resources/WebLibraries/three/addons/lines/LineSegmentsGeometry.js +298 -0
  133. package/Resources/WebLibraries/three/addons/lines/Wireframe.js +108 -0
  134. package/Resources/WebLibraries/three/addons/lines/WireframeGeometry2.js +49 -0
  135. package/Resources/WebLibraries/three/addons/lines/webgpu/Line2.js +46 -0
  136. package/Resources/WebLibraries/three/addons/lines/webgpu/LineSegments2.js +419 -0
  137. package/Resources/WebLibraries/three/addons/lines/webgpu/Wireframe.js +86 -0
  138. package/Resources/WebLibraries/three/addons/loaders/EXRLoader.js +3411 -0
  139. package/Resources/WebLibraries/three/addons/loaders/FBXLoader.js +4660 -0
  140. package/Resources/WebLibraries/three/addons/loaders/FontLoader.js +262 -0
  141. package/Resources/WebLibraries/three/addons/loaders/GLTFLoader.js +5006 -0
  142. package/Resources/WebLibraries/three/addons/loaders/HDRLoader.js +463 -0
  143. package/Resources/WebLibraries/three/addons/loaders/MTLLoader.js +601 -0
  144. package/Resources/WebLibraries/three/addons/loaders/OBJLoader.js +961 -0
  145. package/Resources/WebLibraries/three/addons/loaders/PLYLoader.js +992 -0
  146. package/Resources/WebLibraries/three/addons/loaders/RGBELoader.js +18 -0
  147. package/Resources/WebLibraries/three/addons/loaders/STLLoader.js +423 -0
  148. package/Resources/WebLibraries/three/addons/loaders/SVGLoader.js +3297 -0
  149. package/Resources/WebLibraries/three/addons/loaders/TGALoader.js +539 -0
  150. package/Resources/WebLibraries/three/addons/loaders/UltraHDRLoader.js +757 -0
  151. package/Resources/WebLibraries/three/addons/math/Capsule.js +159 -0
  152. package/Resources/WebLibraries/three/addons/math/ColorConverter.js +62 -0
  153. package/Resources/WebLibraries/three/addons/math/ColorSpaces.js +147 -0
  154. package/Resources/WebLibraries/three/addons/math/ConvexHull.js +1695 -0
  155. package/Resources/WebLibraries/three/addons/math/ImprovedNoise.js +88 -0
  156. package/Resources/WebLibraries/three/addons/math/Lut.js +317 -0
  157. package/Resources/WebLibraries/three/addons/math/MeshSurfaceSampler.js +315 -0
  158. package/Resources/WebLibraries/three/addons/math/OBB.js +535 -0
  159. package/Resources/WebLibraries/three/addons/math/Octree.js +825 -0
  160. package/Resources/WebLibraries/three/addons/math/SimplexNoise.js +470 -0
  161. package/Resources/WebLibraries/three/addons/misc/ConvexObjectBreaker.js +539 -0
  162. package/Resources/WebLibraries/three/addons/misc/GPUComputationRenderer.js +508 -0
  163. package/Resources/WebLibraries/three/addons/misc/Gyroscope.js +78 -0
  164. package/Resources/WebLibraries/three/addons/misc/MorphAnimMesh.js +119 -0
  165. package/Resources/WebLibraries/three/addons/misc/MorphBlendMesh.js +425 -0
  166. package/Resources/WebLibraries/three/addons/misc/ProgressiveLightMap.js +370 -0
  167. package/Resources/WebLibraries/three/addons/misc/ProgressiveLightMapGPU.js +322 -0
  168. package/Resources/WebLibraries/three/addons/misc/RollerCoaster.js +661 -0
  169. package/Resources/WebLibraries/three/addons/misc/Sculptor.js +1679 -0
  170. package/Resources/WebLibraries/three/addons/misc/SculptorMesh.js +1504 -0
  171. package/Resources/WebLibraries/three/addons/misc/SculptorTools.js +1180 -0
  172. package/Resources/WebLibraries/three/addons/misc/SculptorUtils.js +345 -0
  173. package/Resources/WebLibraries/three/addons/misc/TileCreasedNormalsPlugin.js +270 -0
  174. package/Resources/WebLibraries/three/addons/misc/TubePainter.js +611 -0
  175. package/Resources/WebLibraries/three/addons/misc/Volume.js +520 -0
  176. package/Resources/WebLibraries/three/addons/misc/VolumeSlice.js +275 -0
  177. package/Resources/WebLibraries/three/addons/modifiers/CurveModifier.js +374 -0
  178. package/Resources/WebLibraries/three/addons/modifiers/CurveModifierGPU.js +256 -0
  179. package/Resources/WebLibraries/three/addons/modifiers/EdgeSplitModifier.js +299 -0
  180. package/Resources/WebLibraries/three/addons/modifiers/TessellateModifier.js +340 -0
  181. package/Resources/WebLibraries/three/addons/objects/GroundedSkybox.js +69 -0
  182. package/Resources/WebLibraries/three/addons/objects/Lensflare.js +489 -0
  183. package/Resources/WebLibraries/three/addons/objects/LensflareMesh.js +376 -0
  184. package/Resources/WebLibraries/three/addons/objects/MarchingCubes.js +1261 -0
  185. package/Resources/WebLibraries/three/addons/objects/Reflector.js +390 -0
  186. package/Resources/WebLibraries/three/addons/objects/ReflectorForSSRPass.js +393 -0
  187. package/Resources/WebLibraries/three/addons/objects/Refractor.js +389 -0
  188. package/Resources/WebLibraries/three/addons/objects/ShadowMesh.js +130 -0
  189. package/Resources/WebLibraries/three/addons/objects/Sky.js +342 -0
  190. package/Resources/WebLibraries/three/addons/objects/SkyMesh.js +403 -0
  191. package/Resources/WebLibraries/three/addons/objects/Water.js +374 -0
  192. package/Resources/WebLibraries/three/addons/objects/Water2.js +403 -0
  193. package/Resources/WebLibraries/three/addons/objects/Water2Mesh.js +199 -0
  194. package/Resources/WebLibraries/three/addons/objects/WaterMesh.js +194 -0
  195. package/Resources/WebLibraries/three/addons/postprocessing/AfterimagePass.js +187 -0
  196. package/Resources/WebLibraries/three/addons/postprocessing/BloomPass.js +274 -0
  197. package/Resources/WebLibraries/three/addons/postprocessing/BokehPass.js +218 -0
  198. package/Resources/WebLibraries/three/addons/postprocessing/ClearPass.js +97 -0
  199. package/Resources/WebLibraries/three/addons/postprocessing/CubeTexturePass.js +146 -0
  200. package/Resources/WebLibraries/three/addons/postprocessing/DotScreenPass.js +114 -0
  201. package/Resources/WebLibraries/three/addons/postprocessing/EffectComposer.js +365 -0
  202. package/Resources/WebLibraries/three/addons/postprocessing/FXAAPass.js +40 -0
  203. package/Resources/WebLibraries/three/addons/postprocessing/FilmPass.js +113 -0
  204. package/Resources/WebLibraries/three/addons/postprocessing/GTAOPass.js +735 -0
  205. package/Resources/WebLibraries/three/addons/postprocessing/GlitchPass.js +177 -0
  206. package/Resources/WebLibraries/three/addons/postprocessing/HalftonePass.js +134 -0
  207. package/Resources/WebLibraries/three/addons/postprocessing/LUTPass.js +138 -0
  208. package/Resources/WebLibraries/three/addons/postprocessing/MaskPass.js +195 -0
  209. package/Resources/WebLibraries/three/addons/postprocessing/OutlinePass.js +776 -0
  210. package/Resources/WebLibraries/three/addons/postprocessing/OutputPass.js +148 -0
  211. package/Resources/WebLibraries/three/addons/postprocessing/Pass.js +191 -0
  212. package/Resources/WebLibraries/three/addons/postprocessing/RenderPass.js +193 -0
  213. package/Resources/WebLibraries/three/addons/postprocessing/RenderPixelatedPass.js +314 -0
  214. package/Resources/WebLibraries/three/addons/postprocessing/RenderTransitionPass.js +267 -0
  215. package/Resources/WebLibraries/three/addons/postprocessing/SAOPass.js +407 -0
  216. package/Resources/WebLibraries/three/addons/postprocessing/SMAAPass.js +230 -0
  217. package/Resources/WebLibraries/three/addons/postprocessing/SSAARenderPass.js +313 -0
  218. package/Resources/WebLibraries/three/addons/postprocessing/SSAOPass.js +527 -0
  219. package/Resources/WebLibraries/three/addons/postprocessing/SSRPass.js +858 -0
  220. package/Resources/WebLibraries/three/addons/postprocessing/SavePass.js +132 -0
  221. package/Resources/WebLibraries/three/addons/postprocessing/ShaderPass.js +135 -0
  222. package/Resources/WebLibraries/three/addons/postprocessing/TAARenderPass.js +243 -0
  223. package/Resources/WebLibraries/three/addons/postprocessing/TexturePass.js +131 -0
  224. package/Resources/WebLibraries/three/addons/postprocessing/UnrealBloomPass.js +541 -0
  225. package/Resources/WebLibraries/three/addons/shaders/ACESFilmicToneMappingShader.js +96 -0
  226. package/Resources/WebLibraries/three/addons/shaders/AfterimageShader.js +63 -0
  227. package/Resources/WebLibraries/three/addons/shaders/BasicShader.js +36 -0
  228. package/Resources/WebLibraries/three/addons/shaders/BleachBypassShader.js +68 -0
  229. package/Resources/WebLibraries/three/addons/shaders/BlendShader.js +56 -0
  230. package/Resources/WebLibraries/three/addons/shaders/BokehShader.js +151 -0
  231. package/Resources/WebLibraries/three/addons/shaders/BokehShader2.js +404 -0
  232. package/Resources/WebLibraries/three/addons/shaders/BrightnessContrastShader.js +62 -0
  233. package/Resources/WebLibraries/three/addons/shaders/ColorCorrectionShader.js +59 -0
  234. package/Resources/WebLibraries/three/addons/shaders/ColorifyShader.js +57 -0
  235. package/Resources/WebLibraries/three/addons/shaders/ConvolutionShader.js +74 -0
  236. package/Resources/WebLibraries/three/addons/shaders/CopyShader.js +52 -0
  237. package/Resources/WebLibraries/three/addons/shaders/DOFMipMapShader.js +63 -0
  238. package/Resources/WebLibraries/three/addons/shaders/DepthLimitedBlurShader.js +183 -0
  239. package/Resources/WebLibraries/three/addons/shaders/DigitalGlitch.js +104 -0
  240. package/Resources/WebLibraries/three/addons/shaders/DotScreenShader.js +75 -0
  241. package/Resources/WebLibraries/three/addons/shaders/ExposureShader.js +51 -0
  242. package/Resources/WebLibraries/three/addons/shaders/FXAAShader.js +298 -0
  243. package/Resources/WebLibraries/three/addons/shaders/FilmShader.js +73 -0
  244. package/Resources/WebLibraries/three/addons/shaders/FocusShader.js +94 -0
  245. package/Resources/WebLibraries/three/addons/shaders/FreiChenShader.js +103 -0
  246. package/Resources/WebLibraries/three/addons/shaders/GTAOShader.js +437 -0
  247. package/Resources/WebLibraries/three/addons/shaders/GammaCorrectionShader.js +52 -0
  248. package/Resources/WebLibraries/three/addons/shaders/HalftoneShader.js +332 -0
  249. package/Resources/WebLibraries/three/addons/shaders/HorizontalBlurShader.js +68 -0
  250. package/Resources/WebLibraries/three/addons/shaders/HorizontalTiltShiftShader.js +70 -0
  251. package/Resources/WebLibraries/three/addons/shaders/HueSaturationShader.js +74 -0
  252. package/Resources/WebLibraries/three/addons/shaders/KaleidoShader.js +65 -0
  253. package/Resources/WebLibraries/three/addons/shaders/LuminosityHighPassShader.js +68 -0
  254. package/Resources/WebLibraries/three/addons/shaders/LuminosityShader.js +54 -0
  255. package/Resources/WebLibraries/three/addons/shaders/MirrorShader.js +62 -0
  256. package/Resources/WebLibraries/three/addons/shaders/NormalMapShader.js +60 -0
  257. package/Resources/WebLibraries/three/addons/shaders/OutputShader.js +103 -0
  258. package/Resources/WebLibraries/three/addons/shaders/PoissonDenoiseShader.js +230 -0
  259. package/Resources/WebLibraries/three/addons/shaders/RGBShiftShader.js +61 -0
  260. package/Resources/WebLibraries/three/addons/shaders/SAOShader.js +201 -0
  261. package/Resources/WebLibraries/three/addons/shaders/SMAAShader.js +489 -0
  262. package/Resources/WebLibraries/three/addons/shaders/SSAOShader.js +331 -0
  263. package/Resources/WebLibraries/three/addons/shaders/SSRShader.js +396 -0
  264. package/Resources/WebLibraries/three/addons/shaders/SepiaShader.js +57 -0
  265. package/Resources/WebLibraries/three/addons/shaders/SobelOperatorShader.js +98 -0
  266. package/Resources/WebLibraries/three/addons/shaders/SubsurfaceScatteringShader.js +95 -0
  267. package/Resources/WebLibraries/three/addons/shaders/TechnicolorShader.js +51 -0
  268. package/Resources/WebLibraries/three/addons/shaders/ToonShader.js +349 -0
  269. package/Resources/WebLibraries/three/addons/shaders/TriangleBlurShader.js +79 -0
  270. package/Resources/WebLibraries/three/addons/shaders/UnpackDepthRGBAShader.js +60 -0
  271. package/Resources/WebLibraries/three/addons/shaders/VelocityShader.js +137 -0
  272. package/Resources/WebLibraries/three/addons/shaders/VerticalBlurShader.js +66 -0
  273. package/Resources/WebLibraries/three/addons/shaders/VerticalTiltShiftShader.js +70 -0
  274. package/Resources/WebLibraries/three/addons/shaders/VignetteShader.js +56 -0
  275. package/Resources/WebLibraries/three/addons/shaders/VolumeShader.js +285 -0
  276. package/Resources/WebLibraries/three/addons/shaders/WaterRefractionShader.js +106 -0
  277. package/Resources/WebLibraries/three/addons/textures/FlakesTexture.js +54 -0
  278. package/Resources/WebLibraries/three/addons/tsl/WebGLNodesHandler.js +607 -0
  279. package/Resources/WebLibraries/three/addons/tsl/display/AfterImageNode.js +256 -0
  280. package/Resources/WebLibraries/three/addons/tsl/display/AnaglyphPassNode.js +550 -0
  281. package/Resources/WebLibraries/three/addons/tsl/display/BilateralBlurNode.js +377 -0
  282. package/Resources/WebLibraries/three/addons/tsl/display/BleachBypass.js +33 -0
  283. package/Resources/WebLibraries/three/addons/tsl/display/BloomNode.js +599 -0
  284. package/Resources/WebLibraries/three/addons/tsl/display/CRT.js +150 -0
  285. package/Resources/WebLibraries/three/addons/tsl/display/ChromaticAberrationNode.js +163 -0
  286. package/Resources/WebLibraries/three/addons/tsl/display/DenoiseNode.js +354 -0
  287. package/Resources/WebLibraries/three/addons/tsl/display/DepthOfFieldNode.js +572 -0
  288. package/Resources/WebLibraries/three/addons/tsl/display/DotScreenNode.js +104 -0
  289. package/Resources/WebLibraries/three/addons/tsl/display/FSR1Node.js +481 -0
  290. package/Resources/WebLibraries/three/addons/tsl/display/FXAANode.js +357 -0
  291. package/Resources/WebLibraries/three/addons/tsl/display/FilmNode.js +101 -0
  292. package/Resources/WebLibraries/three/addons/tsl/display/GTAONode.js +727 -0
  293. package/Resources/WebLibraries/three/addons/tsl/display/GaussianBlurNode.js +412 -0
  294. package/Resources/WebLibraries/three/addons/tsl/display/GodraysNode.js +604 -0
  295. package/Resources/WebLibraries/three/addons/tsl/display/ImportanceSampledEnvironment.js +564 -0
  296. package/Resources/WebLibraries/three/addons/tsl/display/LensflareNode.js +282 -0
  297. package/Resources/WebLibraries/three/addons/tsl/display/Lut3DNode.js +109 -0
  298. package/Resources/WebLibraries/three/addons/tsl/display/MotionBlur.js +33 -0
  299. package/Resources/WebLibraries/three/addons/tsl/display/OITPassNode.js +341 -0
  300. package/Resources/WebLibraries/three/addons/tsl/display/OutlineNode.js +916 -0
  301. package/Resources/WebLibraries/three/addons/tsl/display/ParallaxBarrierPassNode.js +90 -0
  302. package/Resources/WebLibraries/three/addons/tsl/display/PixelationPassNode.js +227 -0
  303. package/Resources/WebLibraries/three/addons/tsl/display/RGBShiftNode.js +96 -0
  304. package/Resources/WebLibraries/three/addons/tsl/display/RecurrentDenoiseNode.js +812 -0
  305. package/Resources/WebLibraries/three/addons/tsl/display/RetroPassNode.js +263 -0
  306. package/Resources/WebLibraries/three/addons/tsl/display/SMAANode.js +729 -0
  307. package/Resources/WebLibraries/three/addons/tsl/display/SSAAPassNode.js +344 -0
  308. package/Resources/WebLibraries/three/addons/tsl/display/SSAONode.js +422 -0
  309. package/Resources/WebLibraries/three/addons/tsl/display/SSGINode.js +698 -0
  310. package/Resources/WebLibraries/three/addons/tsl/display/SSRNode.js +1430 -0
  311. package/Resources/WebLibraries/three/addons/tsl/display/SSSNode.js +479 -0
  312. package/Resources/WebLibraries/three/addons/tsl/display/Sepia.js +24 -0
  313. package/Resources/WebLibraries/three/addons/tsl/display/Shape.js +29 -0
  314. package/Resources/WebLibraries/three/addons/tsl/display/SharpenNode.js +284 -0
  315. package/Resources/WebLibraries/three/addons/tsl/display/SobelOperatorNode.js +168 -0
  316. package/Resources/WebLibraries/three/addons/tsl/display/StereoCompositePassNode.js +190 -0
  317. package/Resources/WebLibraries/three/addons/tsl/display/StereoPassNode.js +117 -0
  318. package/Resources/WebLibraries/three/addons/tsl/display/TAAUNode.js +700 -0
  319. package/Resources/WebLibraries/three/addons/tsl/display/TRAANode.js +609 -0
  320. package/Resources/WebLibraries/three/addons/tsl/display/TemporalReprojectNode.js +1024 -0
  321. package/Resources/WebLibraries/three/addons/tsl/display/TransitionNode.js +141 -0
  322. package/Resources/WebLibraries/three/addons/tsl/display/boxBlur.js +65 -0
  323. package/Resources/WebLibraries/three/addons/tsl/display/depthAwareBlend.js +80 -0
  324. package/Resources/WebLibraries/three/addons/tsl/display/depthAwareBlur.js +63 -0
  325. package/Resources/WebLibraries/three/addons/tsl/display/hashBlur.js +55 -0
  326. package/Resources/WebLibraries/three/addons/tsl/display/lensDirt.js +30 -0
  327. package/Resources/WebLibraries/three/addons/tsl/display/radialBlur.js +68 -0
  328. package/Resources/WebLibraries/three/addons/tsl/lighting/ClusteredLightsNode.js +994 -0
  329. package/Resources/WebLibraries/three/addons/tsl/lighting/DynamicLightsNode.js +201 -0
  330. package/Resources/WebLibraries/three/addons/tsl/lighting/LightProbeGridNode.js +183 -0
  331. package/Resources/WebLibraries/three/addons/tsl/lighting/data/AmbientLightDataNode.js +67 -0
  332. package/Resources/WebLibraries/three/addons/tsl/lighting/data/DirectionalLightDataNode.js +117 -0
  333. package/Resources/WebLibraries/three/addons/tsl/lighting/data/HemisphereLightDataNode.js +105 -0
  334. package/Resources/WebLibraries/three/addons/tsl/lighting/data/PointLightDataNode.js +140 -0
  335. package/Resources/WebLibraries/three/addons/tsl/lighting/data/SpotLightDataNode.js +167 -0
  336. package/Resources/WebLibraries/three/addons/tsl/math/Bayer.js +84 -0
  337. package/Resources/WebLibraries/three/addons/tsl/math/curlNoise.js +107 -0
  338. package/Resources/WebLibraries/three/addons/tsl/math/voronoiNoise.js +112 -0
  339. package/Resources/WebLibraries/three/addons/tsl/shadows/TileShadowNode.js +542 -0
  340. package/Resources/WebLibraries/three/addons/tsl/shadows/TileShadowNodeHelper.js +212 -0
  341. package/Resources/WebLibraries/three/addons/tsl/utils/GroundedSkybox.js +62 -0
  342. package/Resources/WebLibraries/three/addons/tsl/utils/RNoise.js +51 -0
  343. package/Resources/WebLibraries/three/addons/tsl/utils/Raymarching.js +70 -0
  344. package/Resources/WebLibraries/three/addons/tsl/utils/SoftParticles.js +53 -0
  345. package/Resources/WebLibraries/three/addons/tsl/utils/SpecularHelpers.js +302 -0
  346. package/Resources/WebLibraries/three/addons/tsl/utils/TAAUtils.js +184 -0
  347. package/Resources/WebLibraries/three/addons/utils/BufferGeometryUtils.js +1523 -0
  348. package/Resources/WebLibraries/three/addons/utils/CameraUtils.js +82 -0
  349. package/Resources/WebLibraries/three/addons/utils/ColorUtils.js +76 -0
  350. package/Resources/WebLibraries/three/addons/utils/GaussianSplatUtils.js +229 -0
  351. package/Resources/WebLibraries/three/addons/utils/GeometryCompressionUtils.js +547 -0
  352. package/Resources/WebLibraries/three/addons/utils/GeometryUtils.js +226 -0
  353. package/Resources/WebLibraries/three/addons/utils/LDrawUtils.js +211 -0
  354. package/Resources/WebLibraries/three/addons/utils/SceneOptimizer.js +459 -0
  355. package/Resources/WebLibraries/three/addons/utils/SceneUtils.js +363 -0
  356. package/Resources/WebLibraries/three/addons/utils/ShadowMapViewer.js +244 -0
  357. package/Resources/WebLibraries/three/addons/utils/ShadowMapViewerGPU.js +233 -0
  358. package/Resources/WebLibraries/three/addons/utils/SkeletonUtils.js +496 -0
  359. package/Resources/WebLibraries/three/addons/utils/SortUtils.js +175 -0
  360. package/Resources/WebLibraries/three/addons/utils/UVsDebug.js +173 -0
  361. package/Resources/WebLibraries/three/addons/utils/WebGLTextureUtils.js +115 -0
  362. package/Resources/WebLibraries/three/addons/utils/WebGPUTextureUtils.js +81 -0
  363. package/Resources/WebLibraries/three/addons/utils/WorkerPool.js +167 -0
  364. package/Resources/WebLibraries/three/addons/utils/unwrapUVs.js +865 -0
  365. package/Resources/WebLibraries/three/three.core.js +61162 -0
  366. package/Resources/WebLibraries/three/three.module.js +19537 -0
  367. package/Resources/WebLibraries/three/three.tsl.js +41903 -0
  368. package/Resources/WebLibraries/three/three.webgpu.js +53714 -0
  369. package/Resources/skills/2d-game/SKILL.md +305 -0
  370. package/Resources/skills/3d-game/SKILL.md +274 -0
  371. package/Resources/skills/accounts/SKILL.md +41 -0
  372. package/Resources/skills/android-design/SKILL.md +159 -0
  373. package/Resources/skills/app-ai/SKILL.md +154 -0
  374. package/Resources/skills/app-intents/SKILL.md +31 -0
  375. package/Resources/skills/app-kinds/SKILL.md +122 -0
  376. package/Resources/skills/apple-watch/SKILL.md +43 -0
  377. package/Resources/skills/assets/SKILL.md +183 -0
  378. package/Resources/skills/building-blocks/SKILL.md +97 -0
  379. package/Resources/skills/device-control/SKILL.md +56 -0
  380. package/Resources/skills/device-integrations/SKILL.md +278 -0
  381. package/Resources/skills/finder-files/SKILL.md +19 -0
  382. package/Resources/skills/game/SKILL.md +414 -0
  383. package/Resources/skills/game-3d/SKILL.md +12 -0
  384. package/Resources/skills/game-art/SKILL.md +11 -0
  385. package/Resources/skills/game-feel/SKILL.md +13 -0
  386. package/Resources/skills/game-levels/SKILL.md +12 -0
  387. package/Resources/skills/game-live/SKILL.md +12 -0
  388. package/Resources/skills/game-physics/SKILL.md +13 -0
  389. package/Resources/skills/game-playtest/SKILL.md +26 -0
  390. package/Resources/skills/game-ui/SKILL.md +278 -0
  391. package/Resources/skills/github-projects/SKILL.md +59 -0
  392. package/Resources/skills/icloud-sync/SKILL.md +30 -0
  393. package/Resources/skills/iphone-hardware/SKILL.md +57 -0
  394. package/Resources/skills/iphone-widgets/SKILL.md +53 -0
  395. package/Resources/skills/lg-developer-mode/SKILL.md +152 -0
  396. package/Resources/skills/mac-widgets/SKILL.md +60 -0
  397. package/Resources/skills/maps/SKILL.md +8 -0
  398. package/Resources/skills/menu-bar/SKILL.md +36 -0
  399. package/Resources/skills/more-apps/SKILL.md +53 -0
  400. package/Resources/skills/phone-controllers/SKILL.md +79 -0
  401. package/Resources/skills/phone-pages/SKILL.md +173 -0
  402. package/Resources/skills/roku-developer-mode/SKILL.md +106 -0
  403. package/Resources/skills/scene-3d/SKILL.md +27 -0
  404. package/Resources/skills/scripting/SKILL.md +17 -0
  405. package/Resources/skills/share-extension/SKILL.md +22 -0
  406. package/Resources/skills/tv-design/SKILL.md +72 -0
  407. package/Resources/skills/web-app/SKILL.md +136 -0
  408. package/Resources/skills/web-game/SKILL.md +95 -0
  409. package/Resources/skills/web-or-native/SKILL.md +103 -0
  410. package/Resources/skills/wish-links/SKILL.md +156 -0
  411. package/THIRD_PARTY_NOTICES.md +170 -0
  412. package/cli/android.mjs +941 -0
  413. package/cli/browser.mjs +268 -0
  414. package/cli/calls.mjs +390 -0
  415. package/cli/dev.mjs +773 -0
  416. package/cli/devices.mjs +984 -0
  417. package/cli/lamp.mjs +1016 -0
  418. package/cli/lampapp.mjs +332 -0
  419. package/cli/lamps/android-host/LampPageGateway.kt +345 -0
  420. package/cli/lamps/android-host/app/build.gradle.kts +40 -0
  421. package/cli/lamps/android-host/build.gradle.kts +4 -0
  422. package/cli/lamps/android-host/game/AndroidManifest.xml +33 -0
  423. package/cli/lamps/android-host/game/MainActivity.kt +173 -0
  424. package/cli/lamps/android-host/gradle/libs.versions.toml +39 -0
  425. package/cli/lamps/android-host/gradle.properties +8 -0
  426. package/cli/lamps/android-host/page/AndroidManifest.xml +35 -0
  427. package/cli/lamps/android-host/page/MainActivity.kt +193 -0
  428. package/cli/lamps/android-host/settings.gradle.kts +30 -0
  429. package/cli/lamps/android-host/tools.json +43 -0
  430. package/cli/lamps/lamp-controllers.js +2 -0
  431. package/cli/lamps/lamp-for-games.js +6863 -0
  432. package/cli/lamps/lamp.js +7023 -0
  433. package/cli/lamps/mac-starter/.lamp/meta.json +1 -0
  434. package/cli/lamps/mac-starter/APP.md +12 -0
  435. package/cli/lamps/mac-starter/Package.swift +8 -0
  436. package/cli/lamps/mac-starter/Sources/App.swift +11 -0
  437. package/cli/lamps/mac-starter/Sources/ContentView.swift +17 -0
  438. package/cli/lamps/mac-starter/Sources/LampSupport.swift +18097 -0
  439. package/cli/lamps/mac-starter/build.sh +336 -0
  440. package/cli/lamps/mac-starter/gitignore +3 -0
  441. package/cli/lamps/mac-starter/lamp-starter.json +6 -0
  442. package/cli/lamps/web-starter/APP.md +8 -0
  443. package/cli/lamps/web-starter/app.js +1 -0
  444. package/cli/lamps/web-starter/index.html +17 -0
  445. package/cli/lamps/web-starter/lamp-starter.json +5 -0
  446. package/cli/lamps/web-starter/lamp.js +7023 -0
  447. package/cli/lamps/web-starter/style.css +25 -0
  448. package/cli/link.mjs +138 -0
  449. package/cli/mac.mjs +621 -0
  450. package/cli/mdns.mjs +205 -0
  451. package/cli/msix.mjs +413 -0
  452. package/cli/network.mjs +209 -0
  453. package/cli/outside.mjs +140 -0
  454. package/cli/page.js +165 -0
  455. package/cli/place.mjs +298 -0
  456. package/cli/png.mjs +184 -0
  457. package/cli/share.mjs +202 -0
  458. package/cli/skill/SKILL.md +255 -0
  459. package/cli/skills.mjs +71 -0
  460. package/cli/state.mjs +173 -0
  461. package/cli/update.mjs +57 -0
  462. package/package.json +20 -4
  463. package/site/lib/quota.js +59 -0
  464. package/site/lib/shared-wishes.js +996 -0
@@ -0,0 +1,305 @@
1
+ ---
2
+ name: 2d-game
3
+ description: 2D games - choosing 2D or 3D, and Phaser (a game of Lamp's game kind, played on the Mac, iPhone and iPad, Android, TVs and the Xbox) or SpriteKit (a Mac or iPhone app); scenes, the frame step, cameras, tilemaps, sprite sheets, physics, controls on every input, pixel art, TV safe areas, sound, saves, drawing the art, and keeping it smooth on the slowest place. Read before writing or changing a 2D game; a new web game on the Mac starts from the web-game guide instead, which says when to open this.
4
+ ---
5
+
6
+ # 2D games
7
+
8
+ A 2D game is drawn flat: a platformer, a shooter seen from above or the side, a racer seen from above, a puzzle or
9
+ arcade game played in real time. Read the game skill too: what every game needs (moving by the time since the last
10
+ frame, controls, sound, saves, the look) is there, and this skill is how to do it in 2D.
11
+
12
+ ## 2D or 3D
13
+
14
+ 2D when the person describes something flat (a platformer, "like Mario", "like Pac-Man", a top-down shooter, a pixel-art
15
+ game, a puzzle with falling pieces) or a game whose look is drawings rather than a world to look around. 3D when they
16
+ want depth to move through (driving through a city, flying, a first-person view, a ball rolling over hills): the
17
+ 3d-game skill. When nothing says, a game whose play is flat is better flat: it's cheaper on every device and drawings
18
+ read better than simple 3D shapes. Don't ask; choose, and say in a sentence which.
19
+
20
+ ## Phaser or SpriteKit
21
+
22
+ - **Phaser**, in a game of Lamp's game kind: the page in Web/ on Lamp's game runtime. It's played on the Mac and goes,
23
+ unchanged, to an iPhone or iPad, an Android phone, tablet or TV, a Samsung or LG TV, the Xbox and a page on the web,
24
+ whenever the person asks for one of those later. This is the default for a 2D game.
25
+ - **SpriteKit**, in a Mac or iPhone app written in Swift: when the game belongs with Apple's own things (Game Center,
26
+ a widget, iCloud, the Apple Watch), sits inside an app of theirs (a game in a menu of their Mac app), or is for an
27
+ Apple TV, which runs no pages. A SpriteKit game can never go to Android, the Xbox, a Samsung or LG TV or the web: it
28
+ would have to be written again. Say so plainly when choosing it, and choose it only for what needs it.
29
+
30
+ The kind of app is chosen before your first turn: a game is of the game kind, and a Mac or iPhone app whose request is
31
+ a game is written with SpriteKit. When the choice doesn't fit (a game of the game kind that needs Game Center, or a Mac
32
+ app that should be playable on the person's Xbox), say why in a sentence and change it with make_app_for.
33
+
34
+ ## Phaser on Lamp's runtime
35
+
36
+ Lamp's game kind runs Phaser 3 (3.90) through `Web/lamp-phaser.js`, over the runtime in `Web/lamp-game.js`. Read both,
37
+ all of them, before writing the game: their comments are the interface (a new game at home on the Mac has the
38
+ web-game guide instead). Lamp puts Phaser in `Web/phaser` once the page
39
+ imports it.
40
+
41
+ index.html keeps the scaffold's head (lamp.js, then the import map, whose `phaser` entry is
42
+ `./phaser/phaser.esm.min.js`), then `<script type="module" src="game.js">`. game.js:
43
+
44
+ ```js
45
+ import * as Phaser from 'phaser';
46
+ import { phaser, pad } from './lamp-phaser.js';
47
+ import { BUTTON, STICK, sound, save, load, random, log, label, glyph, onInput, hot } from './lamp-game.js';
48
+
49
+ const CONTROLS = { move: STICK.LEFT, jump: BUTTON.A, back: BUTTON.B, pause: BUTTON.MENU };
50
+
51
+ class Play extends Phaser.Scene {
52
+ constructor() { super('play'); }
53
+ preload() { this.load.image('hero', 'art/hero.png'); }
54
+ create() { … }
55
+ update(time, delta) {
56
+ const p = pad(), dt = delta / 1000;
57
+ if (p.pressed & CONTROLS.jump) …
58
+ }
59
+ }
60
+
61
+ phaser({ scenes: [Boot, Play], physics: { default: 'arcade', arcade: { gravity: { y: 2400 } } }, touch: BUTTON.A | BUTTON.B | BUTTON.MENU });
62
+ ```
63
+
64
+ As the game grows, each scene goes in a module of its own (`play.js` exporting `Play`, imported by game.js) that ends
65
+ with `hot(import.meta).accept()` from lamp-game.js, so a change to it goes into the running scene (the game skill,
66
+ "Changes while it's played"): the scene keeps its sprites and fields and runs the new `update` and the methods it
67
+ calls. What `create` built stays until the scene starts again, so a change to `create` or `preload` returns false from
68
+ `accept((next, { changed }) => !changed.some(n => /\.(create|preload|init)$/.test(n)))` and the game's code runs again
69
+ in place from the snapshot, with a new Phaser game that loads its pictures again.
70
+
71
+ What Lamp has changed in Phaser, so its usual code works here:
72
+
73
+ - **One frame loop, Lamp's.** Phaser's own loop is asleep; each of the runtime's frames steps Phaser once. Use a
74
+ scene's `update(time, delta)` (ms) and Phaser's timers and tweens freely: they all run on that one clock. Never requestAnimationFrame, setTimeout, Date or Math.random of your own:
75
+ `random()` from lamp-game.js, or `Phaser.Math.RND`, which Lamp seeds from it.
76
+ - **Input is the runtime's pad.** `pad()` is the first controller with the keyboard and the touch controls merged in
77
+ (lx, ly, rx, ry with up positive; buttons as BUTTON bits in down, pressed and released). Phaser's keyboard and
78
+ gamepad are off: `this.input.keyboard` and `this.input.gamepad` are null, so never `createCursorKeys` or
79
+ `addKey`. Phaser's pointer input works with the mouse on the Mac; on a touch screen Lamp's touch controls lie over
80
+ the canvas, so a game played by tapping the screen itself passes `touch: false` and reads `this.input.on('pointerdown')`.
81
+ - **Sound is the runtime's.** Phaser's sound is off: `this.load.audio` and `this.sound` play nothing. Load files from the
82
+ `assets` tool (the game skill, "Sound") with `await sound.load('assets/…')`, once, at the top of game.js; `sound.tone`
83
+ makes an effect in code where nothing there fits, in a scene's `create` or at the top of game.js.
84
+ - **The stage is 1920x1080**, fitted to the window or screen with black around it. Lay everything out in those units.
85
+ The page is never resized to the window: don't listen for resize.
86
+ - **Loading.** Load each scene's files in its `preload`, best all in a first Boot scene, and start play from `create`.
87
+ A scene that loads mid-game takes what it takes while the game goes on, so it shows a loading line rather than nothing.
88
+
89
+ ### Structure
90
+
91
+ - **Scenes**: Boot, which loads, then one for each screen of the flow the game picked (the game-ui skill), which is Play
92
+ alone for a game that opens on play. A pause menu is a scene launched over
93
+ play (`this.scene.launch('pause'); this.scene.pause()`), which reads the pad itself and resumes play
94
+ (`this.scene.resume('play'); this.scene.stop()`). Keep the game's state (score, lives, level) in a plain object
95
+ passed in `this.scene.start('play', state)`, not spread over scenes.
96
+ - **A map as a menu**, where the game-ui skill's example suits: the stops in an array, one sprite tweened between them
97
+ with `this.tweens.add` as the choice changes, `this.cameras.main.pan` or `zoomTo` from the view before it, and input
98
+ ignored only for the tween's few frames so a fast press can go on to the next stop. The registered state keeps the stop and the
99
+ camera's position, and `create` sets them directly from it.
100
+ - **The step**: move by `delta`, and give Arcade physics the work of falling, sliding and colliding. Arcade steps its
101
+ world at a fixed 60 times a second whatever the screen's rate (its `fps`, the default), so jumps reach the same
102
+ height on a 120 Hz Mac and a 50 Hz TV. Game logic that must be exact (a puzzle's grid, a rhythm) counts in its own
103
+ fixed steps from `delta`.
104
+ - **Cameras**: `this.cameras.main.setBounds(0, 0, worldWidth, worldHeight)` and `startFollow(hero, true, 0.12, 0.12)`
105
+ with a deadzone (`setDeadzone(300, 200)`), so the screen doesn't jerk with every step. Shake and flash
106
+ (`shake(120, 0.006)`, `flash(150)`) for hits, briefly. The HUD is a second camera's, or HTML over the canvas, never
107
+ moved by the world's camera (`setScrollFactor(0)` on what's drawn in the scene).
108
+ - **Tilemaps**: write each level as rows of characters in code (`'..........#####....'`), each a tile, and build it with
109
+ `this.make.tilemap({ data, tileWidth: 64, tileHeight: 64 })`, `map.addTilesetImage('tiles')` and `map.createLayer(0,
110
+ tileset)`, with `layer.setCollision([...])` and `this.physics.add.collider(hero, layer)`. Rows in code are easy to
111
+ read and change; there's no level editor here. Make the tileset image in code (below) so every tile is the same size.
112
+ - **Sprite sheets and atlases**: frames of one character or thing in one image, `this.load.spritesheet('hero',
113
+ 'art/hero.png', { frameWidth: 64, frameHeight: 64 })`, played with `this.anims.create({ key: 'run', frames:
114
+ this.anims.generateFrameNumbers('hero', { start: 0, end: 5 }), frameRate: 12, repeat: -1 })`. Many small pictures in
115
+ one texture draw in one batch: that's what keeps a busy screen cheap. Pictures made in code are drawn into one
116
+ texture too (`this.textures.createCanvas`, then `texture.add(name, 0, x, y, w, h)` for each frame).
117
+ - **Physics**: Arcade for nearly every game: boxes and circles, gravity, velocity, `collider` and `overlap` with a
118
+ callback. A platformer's player is `this.physics.add.sprite` with `setCollideWorldBounds(true)`; it may jump while
119
+ `body.blocked.down`, with a few frames' grace after leaving a ledge and a jump pressed just before landing still
120
+ taken. Matter (`physics: { default: 'matter' }`) only when things must tumble, stack, swing on joints or have real
121
+ shapes (a physics puzzle, a pile of crates): it costs far more a body and its bodies don't stand still as simply.
122
+ - **Many of a thing** (bullets, coins, enemies, sparks): a group made once with `maxSize` and taken from with
123
+ `group.get(x, y)`. A physics group's member is put back with `disableBody(true, true)` and taken out again with
124
+ `enableBody(true, x, y, true, true)`: hidden and inactive alone, its body still collides and overlaps, so a
125
+ collected coin is collected again and a spent bullet still hits. Sprites without bodies are put back with
126
+ `setActive(false).setVisible(false)`. Particles come from one emitter (`this.add.particles`) with a modest
127
+ `maxParticles`.
128
+
129
+ ### Controls on every input
130
+
131
+ Write the controls once as actions on the pad (CONTROLS above) and read the pad through them. The runtime gives a
132
+ controller, the keyboard and the touch controls as that one pad, so the game needs nothing else. Show how to play, and
133
+ every prompt, from the actions: as HTML over the canvas inside `onInput(draw)`, with `glyph(CONTROLS.jump)` in the
134
+ text ("Press [A] to jump", a badge as the player's input draws it), or in a Phaser Text with `label(CONTROLS.jump)`
135
+ ("A", "✕", "Space"), redrawn from `onInput`. Leave a line out where `label` is null. When the person asked for the arrow
136
+ keys, `phaser({ keyboardHints: { leftStick: 'arrows' }, … })` makes the hints name them (the game skill, "Controls"). On a phone the touch controls show
137
+ a left stick and the buttons `touch` names: give a platformer jump on A and perhaps one more, and keep the game whole
138
+ with those few. Menus move with the stick or the d-pad, choose with A and go back with B; Menu pauses.
139
+
140
+ ### Pixel art or smooth
141
+
142
+ - **Pixel art**: `phaser({ pixelArt: true, … })` keeps every pixel sharp, and the camera zooms by a whole number so
143
+ each art pixel is the same number of screen pixels: `this.cameras.main.setZoom(4)` shows a 480x270 world on the
144
+ 1920x1080 stage (`setZoom(6)` 320x180). Draw the art at that small size, and place things on whole pixels. Never
145
+ scale pixel art by a fraction, or some pixels come out wider than others.
146
+ - **Smooth** (drawings, painted art, vector shapes): leave `pixelArt` off, draw at the size things appear on the
147
+ 1920x1080 stage, and scale pictures down rather than up.
148
+
149
+ ### Safe areas
150
+
151
+ On a TV the edge of the picture may be cut off: keep the score, lives and prompts inside the middle 90% of the stage
152
+ (96 px in from the sides, 54 from the top and bottom), and anything the player must see there too. On a phone Lamp's
153
+ touch controls sit in the bottom corners and small buttons in the top corners: put the HUD at the top center or along
154
+ the top edge between them, never under a thumb.
155
+
156
+ ### Drawing the art
157
+
158
+ Nothing is loaded from the network, ever: the art is in Web/ or made in code.
159
+
160
+ - **Ready-made sprite sheets and tilesets** from the `assets` tool: a platformer's characters with their walk, jump
161
+ and hurt frames, enemies, coins, tiles, a space shooter's ships, a top-down racer's cars and track, pixel-art towns
162
+ and dungeons, UI and icons, each pack in one style. Before drawing a game's characters, enemies and tiles, look
163
+ there (`find` with `show`): a pack's matching frames are what code and `make_art` struggle to give. Open the assets
164
+ skill to choose and to load an XML atlas or a tilesheet with spacing.
165
+
166
+ - **Shapes made in code** are the quickest and always match: draw once with `this.make.graphics({ add: false })`
167
+ (rectangles, circles, rounded boxes, polygons, a gradient of bands) and `generateTexture('coin', 48, 48)`, in a
168
+ Boot scene, then use the texture like any picture. A palette of four to eight colors, used everywhere, makes a game
169
+ look made.
170
+ - **Pixel art in code**: `this.textures.generate('hero', { data: ['..33..', '.3333.', …], pixelWidth: 4 })` draws a
171
+ picture from rows of palette digits (Phaser's 16-color palette, or give `palette`), a frame per call; it's the way to
172
+ get a character's frames the same size and style.
173
+ - **Pictures from `make_art`**: for a character, an object or a background in the style of the game's icon, cut out
174
+ on a transparent background (with `scene` for a whole backdrop). It saves into Assets/: copy what the game uses into
175
+ Web/art/ (`cp Assets/hero.png Web/art/`) and load it from there. Each picture stands alone, so it suits a hero, a
176
+ boss, an item or a backdrop rather than animation frames: move one with tweens (a bob, a squash on landing, a tilt as
177
+ it runs) instead of frames that wouldn't match. Make it once and scale it in the game (`setDisplaySize`).
178
+ - A file the person gave (Attachments/) is copied into Web/ the same way.
179
+
180
+ Whichever way it's drawn, make it read at a glance: characters and objects with recognizable silhouettes, one sprite
181
+ scale and one outline style throughout, a quieter background behind the action, hazards and rewards that never look
182
+ alike, and animation that shows each action (a wind-up, a landing, a hit). Simple geometric art chosen for the game is
183
+ fine.
184
+
185
+ ### Sound and saves
186
+
187
+ The game skill's: look in the `assets` tool first for an effect for each thing the player does or meets and for the
188
+ music, loaded once; `sound.tone` only for what nothing there fits (a jump sliding up, a coin's two quick notes, noise
189
+ for a hit), made once; music quiet or none. The best score, levels reached and settings with
190
+ `save(name, value)` and `load(name)`, read with a default for anything new (`load('best') ?? 0`).
191
+ A registered state keeps the player's place through a change (the scene, its mode, which menu or DOM card is
192
+ open, the player's position, the score, the time), and `busy()` in phaser() holds a change that runs the game's code again during a round (the game skill,
193
+ "Changes while it's played"). A 2D game registers only its state: Phaser's game and cameras are made again from it. The first scene
194
+ goes straight to the scene the state names, and that scene's `create` builds that place with no title card or intro,
195
+ so a fresh start and a change's start are one path:
196
+
197
+ ```js
198
+ const play = hot(import.meta).state('play', {
199
+ version: 1,
200
+ start: () => ({ scene: 'play', mode: 'ready', level: 1, score: 0, paused: false, player: { x: 120, y: 400 } }),
201
+ });
202
+ class Boot extends Phaser.Scene {
203
+ constructor() { super('boot'); }
204
+ preload() { … }
205
+ create() { this.scene.start(play.scene); }
206
+ }
207
+ class Play extends Phaser.Scene {
208
+ constructor() { super('play'); }
209
+ create() {
210
+ play.scene = 'play';
211
+ this.level = buildLevel(play.level);
212
+ this.hero.setPosition(play.player.x, play.player.y);
213
+ if (play.paused) this.showPause(); else if (play.mode === 'ready') hud.card(`Level ${play.level}`);
214
+ }
215
+ update() { play.player.x = this.hero.x; play.player.y = this.hero.y; … }
216
+ }
217
+ ```
218
+
219
+ A picture Phaser's loader read goes in again through `assetChanged(path)` in phaser() (load it again and
220
+ swap the texture), or the game's code runs again in place from the state.
221
+
222
+ ### Keeping it smooth on the slowest place
223
+
224
+ The slowest places are an Xbox One in Developer Mode, a cheap Android phone or TV stick and a Samsung or LG TV's
225
+ browser; the request's device line names the slowest this game is played on and its budget. In 2D what costs is draws and filling the screen, rarely shapes:
226
+
227
+ - few textures: sprites that share one texture (an atlas, or the shapes made into one canvas texture) are drawn in
228
+ one batch, and every change of texture starts another;
229
+ - a Text object redraws its whole picture when its text changes: change it only when the number does, never every
230
+ frame (or use HTML over the canvas for the HUD);
231
+ - a Graphics object drawn in play is redrawn every frame: make it a texture once instead;
232
+ - layers of big pictures over the whole screen (parallax backgrounds, a full-screen overlay) each fill the screen
233
+ again: two or three at most on a TV;
234
+ - effects (`preFX`, `postFX`, glow, blur, bloom) are full extra passes: none on a TV or an Xbox One;
235
+ - no allocation per frame, and pools for what comes and goes; Arcade rather than Matter.
236
+
237
+ The log on a device says every ten seconds how many frames a second it gets there: when it's short of 60, draw less.
238
+
239
+ ### Checking it
240
+
241
+ `look_at_app` shows the game in its window on this Mac, where the person is in it, opening it when it's closed;
242
+ `use_app` plays it there with Lamp's own controller (`stick`, `button`, `wait`, and a `click` on what its screen shows), from wherever it is, a picture at the
243
+ end (the game skill, "Playtesting"). When the person asks you to try, play or test it, play it as they would: start
244
+ it, jump, die, win, pause, change a setting and come back to find it kept. Once it looks or plays right there,
245
+ `look_at_app` with `on_device` looks at it in the preview of where Try On points (the iPhone or iPad simulator); the
246
+ person's own iPhone, iPad or Xbox is only for their Play.
247
+
248
+ ## SpriteKit in a Mac or iPhone app
249
+
250
+ The game is an `SKScene` subclass for each screen, shown in SwiftUI with `SpriteView`, with SwiftUI over it for the
251
+ score, menus and prompts (the game-ui skill says how to choose a game's screens and how they look):
252
+
253
+ ```swift
254
+ import SwiftUI
255
+ import SpriteKit
256
+
257
+ struct GameScreen: View {
258
+ @State private var scene = PlayScene(size: CGSize(width: 1920, height: 1080))
259
+ var body: some View {
260
+ SpriteView(scene: scene, preferredFramesPerSecond: 60, options: [.ignoresSiblingOrder])
261
+ .ignoresSafeArea()
262
+ .overlay(alignment: .top) { ScoreBar(score: scene.score) }
263
+ }
264
+ }
265
+ ```
266
+
267
+ Make the scene once (`@State`), never in `body`. A scene of a fixed size with `scaleMode = .aspectFit` is laid out
268
+ once and letterboxed on any window, like the game kind's stage; `.resizeFill` with an `SKCameraNode` following the
269
+ player shows more of a big world on a big window. What SwiftUI shows over it (the score, lives, a pause) comes from
270
+ the scene as `@Observable` (Observation), which `@State` holds as above; a scene that is an `ObservableObject` with
271
+ `@Published` values is held with `@StateObject` instead, or the view never sees them change.
272
+
273
+ - **The step**: `update(_ currentTime:)` works out the time since the last frame (at most 1/20 s, so a pause doesn't
274
+ jump) and moves by it; physics bodies move themselves. Logic that must be exact counts fixed steps of 1/60 s from it.
275
+ - **Cameras**: an `SKCameraNode`, `scene.camera = cam`, moved toward the player each frame (`cam.position +=
276
+ (target - cam.position) * min(1, dt * 8)`) and kept inside the level; the HUD is SwiftUI, or nodes added to the
277
+ camera.
278
+ - **Tiles**: for a level of rows in code, a sprite per tile is fine to a few thousand; past that, draw the level's still
279
+ part once into one texture (`view.texture(from: node)`) and show that. `SKTileMapNode` with a tile set made in code
280
+ works too, for a big grid.
281
+ - **Sprite sheets**: one picture cut into frames with `SKTexture(rect:in:)` (the rect in 0-1 of the sheet), played with
282
+ `SKAction.animate(with:timePerFrame:)`. Textures of one `SKTextureAtlas`, or cut from one sheet, draw in one batch.
283
+ - **Physics**: `SKPhysicsBody(rectangleOf:)` or `(circleOfRadius:)`, each with its `categoryBitMask`,
284
+ `collisionBitMask` and `contactTestBitMask`, and the scene as `physicsWorld.contactDelegate` hearing
285
+ `didBegin(_:)`. A platformer's ground is one body for each run of tiles side by side, not one per tile, so the player
286
+ doesn't catch on the seams; give the player `allowsRotation = false` and set its velocity rather than pushing it.
287
+ - **Controls**: a controller through GameController, read each frame from `GCController.current?.extendedGamepad`
288
+ (`leftThumbstick`, `dpad`, `buttonA`…, and `buttonMenu` to pause); on the Mac the keys with
289
+ `NSEvent.addLocalMonitorForEvents(matching: [.keyDown, .keyUp])`, keeping the keys held in a set and returning nil
290
+ for the game's keys (so they don't beep); on an iPhone, touch: `GCVirtualController` with a left stick and one or
291
+ two buttons draws them over the game and reads as a controller, so one reading covers both. Name a controller's
292
+ buttons from the controller itself (`buttonA.sfSymbolsName` as an `Image(systemName:)`, or `localizedName`), never
293
+ a fixed letter, and keys by the key ("Space", "←").
294
+ - **Pixel art**: `texture.filteringMode = .nearest` on every texture, positions rounded to whole pixels, and the scene
295
+ scaled by a whole number.
296
+ - **Sound and saves**: as the game skill says for Swift (files with AVAudioPlayer or effects made once with AVAudioEngine, `.ambient` on iPhone),
297
+ and the best score and settings in LampStore.
298
+ - **Game Center** (`GKLocalPlayer.local.authenticateHandler`, leaderboards) works only in an app signed for the
299
+ person's Apple team with Game Center on: keep the game whole without it, scores in LampStore as well.
300
+ - **Art**: as above: shapes in code (`SKShapeNode` drawn once into a texture with `view.texture(from:)`, since a shape
301
+ node is costly to draw), pictures from `make_art` in Assets/ loaded once with `LampAssets.image("hero.png").map(SKTexture.init(image:))`.
302
+
303
+ Look with `look_at_app` (with `motion` for what moves), and use it with `use_app`, keys and clicks, when the person
304
+ asks you to try it: the game skill's "Playtesting" says what to say otherwise. Its "Keeping every frame smooth" holds
305
+ here too.
@@ -0,0 +1,274 @@
1
+ ---
2
+ name: 3d-game
3
+ description: 3D games and scenes in a web page with three.js, on any device that runs web, TVs included - which library 3D is drawn with, loading it and the renderer on Lamp's game runtime or in a TV or device page, models, light and materials, physics with Rapier (things that fall, roll, stack and collide, a player that walks on them, a car on its wheels), and what costs the most. Read before writing or changing 3D in a web page.
4
+ ---
5
+
6
+ # 3D in a web page
7
+
8
+ three.js runs in a page wherever the device takes a page (`make_app_for`'s table) and its browser gives WebGL 2: a
9
+ host for the page isn't enough on its own, so check WebGL 2 first (below). What differs then is speed: a Mac draws far
10
+ more than a phone, and a TV's chip is often slower than a phone's. Nothing here limits what you make; it says what
11
+ costs the most, so you can choose what the game is worth on the devices it's played on.
12
+
13
+ Lamp ships three.js in two kinds of page: a game's page on its runtime (`make_app_for` with `kind` "game"), and a page
14
+ with no runtime: a Samsung or LG TV app's page, or a device integration's web app whose rules name the 3D library's folder. A page with no
15
+ runtime has no game runtime, no Phaser bridge and no Rapier: it loads three.js from the folder its rules give and makes
16
+ its own renderer and frame loop (below).
17
+
18
+ A 3D game is made this way by default, on every device Lamp has a host for a page on, the Mac included. 3D in Swift,
19
+ in a Mac app made natively (because the person asked for native, or the app was made so), is the scene-3d skill's
20
+ (RealityKit through LampSceneView); native 3D on iPhone, iPad or Apple TV is written with that device's own
21
+ frameworks. A game whose play is flat is better made in 2D with Phaser (the 2d-game skill), which also runs where a
22
+ TV's browser has no WebGL 2. The game skill holds what every game needs
23
+ (the frame loop, controls, sound, saves); read it too.
24
+
25
+ A menu that's a place (the game-ui skill) is a list of stops with a camera position for each, eased between in `frame`,
26
+ with the stop in the game's registered state and the camera registered (the game skill, "Changes while it's played").
27
+
28
+ ## The renderer
29
+
30
+ ### A game on Lamp's runtime
31
+
32
+ index.html loads lamp.js, then the scaffold's import map, then game.js as a module: keep that. The import map's
33
+ `three` and `three/addons/` come from `Web/three`: the WebGL build and its addons such as GLTFLoader. `three/webgpu`
34
+ and `three/tsl` (node materials, drawing with WebGL 2) are added once the page imports them, and only a heavy scene
35
+ needs them. Nothing else is there, so no Draco or KTX2 files (the `assets` tool brings in none), and nothing is
36
+ loaded from the network. Physics is
37
+ Rapier, mapped in the import map when a game needs it (Physics, below).
38
+
39
+ game.js registers one renderer, `live.renderer(() => new THREE.WebGLRenderer({ antialias: true }))` (with
40
+ `const live = hot(import.meta)`), each camera with `live.camera(id, build)` and its state with `live.state` (the game
41
+ skill, "Changes while it's played", has the recipe), and calls `game({ renderer, init, frame, touch })` from
42
+ lamp-game.js once. A `WebGPURenderer` is made and given its `await r.init()` in an async build:
43
+ `const renderer = await live.renderer(async () => { const r = new THREE.WebGPURenderer(); await r.init(); return r; })`.
44
+
45
+ - Lamp sizes the canvas to 1920x1080 and fits it to the window or screen.
46
+ - `init` runs once, before the first frame. It may be async, to load models with
47
+ `new GLTFLoader().loadAsync('ship.glb')` or sounds; make or load every sound here. It builds what the state says:
48
+ the level, the player and the open menu or overlay from the registered state, which is already back after a change
49
+ of the code, and the opening (a title, an intro, a briefing) only when `play.mode` says so (the game skill, "Changes
50
+ while it's played"; the game-ui skill says how a game opens and what its menus are). A camera's start pose goes in its `build`, never here.
51
+ - `frame(f)` runs about 60 times a second. It reads the controller as `f.pads[0]`, moves things by `f.dt` (and
52
+ `f.time`), and ends with `renderer.render(scene, camera)`.
53
+ - `touch` names the buttons Lamp's touch controls show on a phone or tablet.
54
+ - game.js only puts the parts together, and keeps the scene, the lights and the world's parts with
55
+ `hot(import.meta).keep` (the game skill, "Changes while it's played", has the recipe). The world is built in parts (the ground, the
56
+ buildings, the trees and street details, the props, the traffic), each in a module of its own and into a group of
57
+ its own, kept with the data it's built from as its `from`, so a change to one part or its data builds only that
58
+ part again, and a part that's slow to build (the city, the terrain, the traffic) with `background: true`, built in
59
+ steps or with a worker, so the game plays on while it's built (the game skill's recipe); each thing that moves or changes in play (the player,
60
+ a vehicle, the camera, enemies, the HUD's code) is a class in a module that ends with `hot(import.meta).accept()`,
61
+ so a change to its methods goes into the running scene with nothing built again. A uniform's value or a material's
62
+ color set in an `update` swaps; a material made anew compiles its shader again, which Lamp does before the
63
+ first frame after a change while the frame before stays on screen, so a world's materials are made in its kept parts.
64
+
65
+ A page laid out at the window's size whose HUD is its own HTML (a strategy game, a page made for phones as well as
66
+ TVs) passes `fill: true` to `game()` and places and sizes its canvas itself, drawing it smaller when frames run slow;
67
+ the rest of this section is for a game drawn at 1920x1080.
68
+
69
+ When frames run slow, Lamp draws the game smaller and scales it up to the screen by itself (`sharp: true` in `game()`
70
+ keeps it at 1920x1080), so size anything drawn off-screen (a render target, a post-process pass) from
71
+ `renderer.getSize()`, never from 1920x1080. Read lamp-game.js's comments first: they're the whole interface.
72
+
73
+ ### A page with no runtime (a TV app, a device's web app)
74
+
75
+ The page's rules name the folder Lamp writes three.js in and the path the page reaches it at (`./three/` in a Samsung
76
+ or LG TV app's Web/). Lamp writes that folder before every build: never edit it. In index.html, after lamp.js, put the
77
+ import map with that path:
78
+
79
+ ```html
80
+ <script type="importmap">{ "imports": { "three": "./three/three.module.js", "three/addons/": "./three/addons/" } }</script>
81
+ ```
82
+
83
+ then the 3D code in a `<script type="module">` (or a module file of your own beside it), with
84
+ `import * as THREE from 'three'` and addons from `'three/addons/…'`. Use this three.js for anything 3D, never another
85
+ engine or one from the network. Make the renderer yourself, sized to 1920x1080 at a pixel ratio of 1 (the page is laid
86
+ out at that size and scaled), and draw from your own `requestAnimationFrame`, moving everything by the time since the
87
+ last frame. Modules and import maps need a newer TV browser than the oldest the TV rules allow for, and three.js needs
88
+ WebGL 2 (next).
89
+
90
+ The three.js Lamp ships asks the browser only for a WebGL 2 context and stops with an error when it gets none, so
91
+ WebGL 2 comes before anything else here: check on the device that a canvas gives one (log whether
92
+ `canvas.getContext('webgl2')` returns a context, and ask the person to try it there with Play, since Lamp's looks
93
+ never reach their device). Most browsers
94
+ have it; not every Samsung TV does. Where it's missing, make the game another way (2D with Phaser, which draws with WebGL 1 or a plain canvas, or native on that
95
+ device) or tell the person why 3D in a page can't run there.
96
+
97
+ ## Models, light and materials
98
+
99
+ - Before building a game's buildings, vehicles, characters or trees in code, look in Lamp's free models (`assets` with
100
+ `find` and `show`; the assets skill): many distinct things, and anything that walks or runs, come out better
101
+ ready-made. Shapes made in code (boxes, spheres, cylinders, extruded outlines), well lit and colored, often look better than
102
+ mismatched models, and cost little. Build each character and prop as a `THREE.Group` of them in a function of its
103
+ own (a body, a head, eyes that blink, wheels that turn, a tail that wags), its parts named so they can move, and
104
+ give it a little life: a bob, a lean into a turn, a squash on landing. A model file (a .glb) is one the person
105
+ gave or named, or a ready-made one from the `assets` tool (buildings, vehicles, characters with animations, trees:
106
+ the assets skill says when they suit and how to scale, turn, copy and animate them). It goes in Web/ and loads once
107
+ in `init` with lamp-game.js's `model('ship.glb')` (a group holding its scene, with `group.animations`), and a picture with
108
+ `texture('bricks.png', t => { t.colorSpace = THREE.SRGBColorSpace; })`: a new copy of either goes into the running
109
+ game, inside the same group or texture. A clone of the model, or a mixer playing its animations, is made again in
110
+ `assetChanged(path)` (the game skill, "Changes while it's played").
111
+ - One or two lights computed in the shader are the safe start. MeshStandardMaterial looks good under them;
112
+ MeshLambertMaterial or MeshBasicMaterial cost less.
113
+ - Make every mesh, material and texture once in `init` and reuse it; many copies of one shape are one
114
+ `THREE.InstancedMesh`.
115
+ - Compose the view, within the same budget: a camera framing what the player needs to see ahead, things at one
116
+ consistent scale, light that separates the player and hazards from the ground, and contact cues (a blob shadow, a
117
+ dust puff) that put things on the ground instead of floating.
118
+
119
+ ## Physics
120
+
121
+ **Whether a game needs it.** Most don't. A runner, a shooter, a racer on a track or a platformer on flat ground moves
122
+ things by its own rules and tests what touches what itself: the distance between two centers, two boxes
123
+ (`THREE.Box3`), a ray down to the ground over a few meshes (`THREE.Raycaster`). That costs nearly nothing and does
124
+ exactly what the game means. Physics is for games whose fun is things behaving like things: a stack of crates that
125
+ topples, marbles that roll and knock into each other, a board that tilts, a ball through pins, a car on its
126
+ suspension, a door on a hinge, a chain, a pile of anything. Once a game starts writing its own bounces, stacking or
127
+ rolling, it wants physics: hand-made physics is where objects sink, jitter and pass through walls.
128
+
129
+ **Rapier.** Lamp ships Rapier, a physics engine in WebAssembly, as one module that loads like three.js does,
130
+ wherever the game is played. It's for a game's page on its runtime; a TV app's page doesn't get it. Add it to the import map in index.html,
131
+ `"@dimforge/rapier3d-compat": "./rapier/rapier.js"`, and Lamp puts `Web/rapier/` beside the page (it's Lamp's, like
132
+ `Web/three/`; a game that doesn't import it doesn't carry it). Start it once, in `init`, and step the world with
133
+ `fixedStep` from lamp-game.js:
134
+
135
+ ```js
136
+ import * as THREE from 'three';
137
+ import RAPIER from '@dimforge/rapier3d-compat';
138
+ import { game, fixedStep } from './lamp-game.js';
139
+
140
+ let world, events, physics, pad, presses = 0;
141
+ game({ renderer, async init() {
142
+ await RAPIER.init();
143
+ world = new RAPIER.World({ x: 0, y: -9.81, z: 0 });
144
+ events = new RAPIER.EventQueue(true);
145
+ physics = fixedStep(() => { steer(); world.step(events); events.drainCollisionEvents(hit); });
146
+ // … the ground, the bodies and their meshes
147
+ }, frame(f) {
148
+ pad = f.pads[0];
149
+ presses |= pad.pressed; // kept until a step uses them
150
+ physics(f.dt);
151
+ place();
152
+ renderer.render(scene, camera);
153
+ } });
154
+
155
+ function steer() {
156
+ // Held buttons and sticks are read as they are now, every step.
157
+ ball.applyImpulse({ x: pad.lx * PUSH, y: 0, z: -pad.ly * PUSH }, true);
158
+ // A press is used by one step only: a frame can run no step (at 120 frames a second) or two (at 30).
159
+ if (presses & CONTROLS.jump) ball.applyImpulse({ x: 0, y: JUMP, z: 0 }, true);
160
+ presses = 0;
161
+ }
162
+ ```
163
+
164
+ - `await RAPIER.init()` goes inside `init` (never at the top of the module), so a failure is the game's start-up
165
+ error, which the game's log and the look report.
166
+ - The world steps 1/60 s at a time (`world.timestep`, its default), the step `fixedStep` runs as often as the frame
167
+ needs, so the game plays the same at 30, 60 or 120 frames a second. Never pass `f.dt` to the world or change `timestep` per frame. Anything that
168
+ pushes bodies (the controls, a motor) runs inside the step, as `steer()` does above, reading the pad the frame
169
+ kept. A press (`pressed`, `released`) belongs to a frame, not a step: gather it into `presses` in `frame` and let the
170
+ first step that runs use it and clear it, or a jump is lost at 120 frames a second and done twice at 30. Anything
171
+ random in the setup comes from `random()`.
172
+ - Meters, kilograms and seconds, y up, as three.js has them. Keep things their real size: a box a meter across, a
173
+ marble a few centimeters. Rapier's tolerances are tuned for things about a meter across: in a world of small things
174
+ (a tabletop maze, marbles, dice) set `world.lengthUnit` to their typical size in meters (0.05 for marbles), or they
175
+ sink into each other and jitter. Small fast things can pass through thin walls between steps: make walls thick, or
176
+ give the fast body `setCcdEnabled(true)`.
177
+
178
+ **Bodies and colliders.** A body is how a thing moves; its colliders are its shape.
179
+
180
+ - Fixed (`RigidBodyDesc.fixed()`): what never moves, the ground, walls, the track.
181
+ - Dynamic (`RigidBodyDesc.dynamic()`): moved only by physics, crates, balls, debris. Push it with `applyImpulse` (a
182
+ kick) or `addForce` (a steady push), never by setting its position each frame.
183
+ - Kinematic (`RigidBodyDesc.kinematicPositionBased()`): moved by the game, pushing dynamic bodies without being
184
+ pushed back: a moving platform, a tilting board, a door the game opens. Give it its place each step with
185
+ `setNextKinematicTranslation` and `setNextKinematicRotation`.
186
+
187
+ Colliders are simple shapes: `ColliderDesc.cuboid`, `ball`, `capsule`, `cylinder`, `roundCuboid` (a box with
188
+ rounded edges rolls and stacks more kindly), several on one body for a shape made of parts (a table: a top and four
189
+ legs). A model's look never becomes its collider: an odd shape that moves is a `convexHull` of a few of its points,
190
+ a level that never moves may be a `trimesh` of a simplified mesh, and land is a `heightfield`. Bounce, grip and weight
191
+ are the collider's: `setRestitution`, `setFriction`, `setDensity`.
192
+
193
+ **Meshes in step with bodies.** Keep each body with the mesh that shows it and copy the body onto the mesh after the
194
+ step, straight into three.js's own objects, so nothing is allocated per frame:
195
+
196
+ ```js
197
+ const things = []; // { body, mesh }
198
+ function place() {
199
+ for (const t of things) { t.body.translation(t.mesh.position); t.body.rotation(t.mesh.quaternion); }
200
+ }
201
+ ```
202
+
203
+ Many of one thing (a hundred crates) are one `THREE.InstancedMesh`: read each body into one Vector3 and Quaternion
204
+ kept for it, `matrix.compose(position, quaternion, scale)`, `setMatrixAt(i, matrix)`, and set `instanceMatrix.needsUpdate`.
205
+
206
+ **The player.** A character that walks, climbs steps and stands on slopes is a kinematic body with a capsule and
207
+ Rapier's character controller, rather than a dynamic ball pushed around:
208
+
209
+ ```js
210
+ const controller = world.createCharacterController(0.02);
211
+ controller.enableAutostep(0.3, 0.2, true); // steps up to 30 cm
212
+ controller.enableSnapToGround(0.3);
213
+ controller.setMaxSlopeClimbAngle(45 * Math.PI / 180);
214
+ // each step: where the player wants to go this step, gravity included
215
+ controller.computeColliderMovement(playerCollider, wanted);
216
+ const moved = controller.computedMovement(), at = playerBody.translation();
217
+ playerBody.setNextKinematicTranslation({ x: at.x + moved.x, y: at.y + moved.y, z: at.z + moved.z });
218
+ const grounded = controller.computedGrounded(); // may jump
219
+ ```
220
+
221
+ The game keeps the player's own vertical speed (gravity added each step, set on a jump, zeroed when grounded).
222
+
223
+ **A vehicle.** A car is a dynamic body (a box for the chassis, its weight low) and Rapier's vehicle controller, which
224
+ casts a ray for each wheel and gives it suspension and grip:
225
+
226
+ ```js
227
+ const car = world.createVehicleController(chassis);
228
+ const down = { x: 0, y: -1, z: 0 }, axle = { x: -1, y: 0, z: 0 };
229
+ for (const [x, z] of [[-0.8, 1.3], [0.8, 1.3], [-0.8, -1.3], [0.8, -1.3]]) car.addWheel({ x, y: 0, z }, down, axle, 0.3, 0.35);
230
+ // each step: steering on the front wheels, engine and brake on the back
231
+ car.setWheelSteering(0, steer); car.setWheelSteering(1, steer);
232
+ car.setWheelEngineForce(2, gas); car.setWheelEngineForce(3, gas);
233
+ car.updateVehicle(world.timestep);
234
+ ```
235
+
236
+ Wheels are drawn from the controller (`wheelSuspensionLength(i)`, `wheelRotation(i)`, `wheelSteering(i)`), not given
237
+ bodies of their own. Tune `setWheelFrictionSlip` and the suspension by driving it in its window (`use_app`).
238
+
239
+ **Joints** hold two bodies together: `RAPIER.JointData.revolute` (a hinge: a door, a wheel, a flipper),
240
+ `prismatic` (a slider), `spherical` (a ball joint: a chain link, a pendulum), `fixed` (welded), made with
241
+ `world.createImpulseJoint(data, body1, body2, true)`. A hinge can be driven with `configureMotorVelocity`.
242
+
243
+ **What touched what.** Give a collider `setActiveEvents(RAPIER.ActiveEvents.COLLISION_EVENTS)` and read
244
+ `events.drainCollisionEvents((a, b, started) => …)` after each step, a pair of collider handles: keep a `Map` from
245
+ handle to the game's thing. A sensor (`setSensor(true)`) is a zone that's felt but not hit: a goal, a pickup, a
246
+ checkpoint. A collision is the moment for a sound and a rumble.
247
+
248
+ **Keeping it light.** Physics runs on the CPU, before anything is drawn, so it takes from the same 16 ms. Resting
249
+ bodies fall asleep by themselves and then cost almost nothing: leave them be (don't set their position or velocity
250
+ unless something happens to them), and when the game moves a sleeping one itself, `wakeUp()` it. Balls, boxes and
251
+ capsules are cheapest; convex hulls cost more, trimeshes most. Where the request's device line names a slow place
252
+ (a TV, a streamer, an older console), keep to about 100 dynamic bodies awake at once, with a few hundred more asleep or
253
+ fixed; a Mac takes a thousand. Step only through `fixedStep`, never make a body or collider per frame (make them in `init` or when a level starts, and reuse them), and remove what
254
+ falls out of the world (`world.removeRigidBody`). The device's log says how its frames keep to time: when they're late
255
+ with physics in play, make fewer bodies move at once before drawing less.
256
+
257
+ ## What costs the most
258
+
259
+ Roughly in order: shadow maps (each light that casts one draws the scene again), full-screen effects
260
+ (post-processing, bloom), many lights, a high pixel ratio (lamp-game.js already draws at 1, never at the screen's own),
261
+ many draw calls (each distinct mesh and material), large textures, and many triangles.
262
+
263
+ ## On a TV
264
+
265
+ Some platforms might not be powerful enough to run three.js.
266
+
267
+ ## Checking it
268
+
269
+ `look_at_app` shows the game in its window on this Mac, where the person is in it, opening it when it's closed; its
270
+ log says every ten seconds how it kept to its frames there, which says nothing of a slower device's: keep to the budget
271
+ in the request's device line. `use_app` plays it there with Lamp's own controller. `look_at_app` with `on_device` looks
272
+ at the game in the preview of where Try On points (the iPhone or iPad simulator), never the person's own device, so its
273
+ frame times there say nothing of a phone's either.
274
+ When the person asks you to try, play or test it, play it as the game skill's "Playtesting" says.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: accounts
3
+ description: The person's calendar, reminders, contacts, mail and cloud files through the accounts already on the device, and on a Mac what lives in another app they use (LampComputer). Read before an app reaches any of them, including when a wish names a service such as "my Google Calendar".
4
+ ---
5
+
6
+ # The person's own accounts and apps
7
+
8
+ When a wish needs the person's calendar, reminders, contacts, mail or files, reach first for what the device is
9
+ already signed in to, before any service's API, sign-in, key or connector.
10
+
11
+ ## Calendar, reminders and contacts (Mac and iPhone)
12
+
13
+ They come through the accounts already on the device (iCloud, Google, Exchange, Outlook), with no sign-in or key, from
14
+ LampSupport.swift: `LampCalendar.events(from:to:)` / `.add(...)`, `LampReminders.open()` / `.add(...)` /
15
+ `.complete(id)`, `LampContacts.search("name")` / `.find(email:)`.
16
+
17
+ ## Mail and files (Mac only)
18
+
19
+ - Email: `LampMail.inbox(limit:)` / `.search(text)` / `.body(of:)` / `.draft(to:subject:body:)` (a draft opens in Mail
20
+ for the person to send; nothing is sent by the app).
21
+ - Their files in Google Drive, Dropbox, OneDrive or iCloud Drive are folders on the Mac: `LampFolders.synced` lists
22
+ them and `LampFolders.synced("Google Drive")` gives one; read, write and watch them as files.
23
+
24
+ ## What a service's name means
25
+
26
+ A wish that names a service ("my Google Calendar", "my Gmail", "my Outlook contacts", "my Dropbox") means these:
27
+ never call the service's web API, never ask for a key, a sign-in or a developer registration, and don't ask which
28
+ service they use. When their account or folder isn't on the Mac, the app says in one line where to add it (System
29
+ Settings → Internet Accounts, the service's own Mac app, or Mail) and works once it's there. macOS and iOS ask the
30
+ person once per kind of data; each call throws a plain message if refused, so show `error.localizedDescription`.
31
+
32
+ ## Another app the person uses (Mac only)
33
+
34
+ When the information or the job lives in another app the person uses and the accounts and synced folders above and
35
+ `connectors` can't reach it (Slack, Messages, Notes, or a site in their browser such as LinkedIn or a CRM), use
36
+ `LampComputer.ask("…")` to read it or `LampComputer.perform("…")` to act there, from LampSupport.swift. It works with
37
+ what they're already signed in to, with no API keys or connectors, and returns text (ask for JSON in the task when
38
+ the app needs structure). Calls take 10–60 seconds, so run them when the person asks (a button), never on a timer,
39
+ and show progress. `perform` asks the person before every click or keystroke. Prefer files, LampText and the web when
40
+ they can do the job, and prefer the accounts above to LampComputer for mail, calendar, people and files: they're
41
+ instant and free.