@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,60 @@
1
+ ---
2
+ name: mac-widgets
3
+ description: A Mac app's widget for the desktop and Notification Center (Widget/) - how it's written and drawn, the data the app hands it, buttons in it, a widget with no app window, and what to tell the person. Read before writing or changing anything in Widget/.
4
+ ---
5
+
6
+ # A widget for the desktop and Notification Center
7
+
8
+ ## Writing it
9
+
10
+ Write it with WidgetKit and SwiftUI in a `Widget/` folder at the app's root, beside Sources/, starting with
11
+ Widget/Widget.swift: one `@main`, on the `Widget` or on a `WidgetBundle` for several. Lamp builds that folder into the
12
+ app as its widget. It is a separate program that shares no code with Sources/: nothing from LampSupport.swift exists
13
+ there, and a type both sides need is written on both.
14
+
15
+ - Use `StaticConfiguration` with a `TimelineProvider`, a `configurationDisplayName` and `description` in the user's
16
+ words, `supportedFamilies` from .systemSmall, .systemMedium and .systemLarge, and
17
+ `.containerBackground(for: .widget) { … }` on the view, without which it shows nothing.
18
+ - Put `.lampWand()` on each widget's whole view too (`.lampWand(edgeToEdge: true)` with `.contentMarginsDisabled()`):
19
+ it's Lamp's wand in the top right corner, which opens the app's chat, so leave that corner empty.
20
+ - A widget is a picture macOS redraws from the timeline, not a running view: no timers, animation, scrolling or text
21
+ fields. `Text(date, style: .timer)` and `.relative` count by themselves, entries dated ahead change it on
22
+ schedule, and macOS refreshes it when it chooses, minutes apart at best. It may load from the web with URLSession.
23
+
24
+ ## The app's data
25
+
26
+ The widget can't read what the app has saved (LampStore, files, settings), so the app hands it over:
27
+
28
+ - In the app, `LampWidget.share(Summary(…), as: "summary")` with any Codable value, at launch and whenever the data
29
+ changes (it also redraws the widget).
30
+ - In the widget, `LampWidget.read(Summary.self, from: "summary") { summary in … }` in getSnapshot and getTimeline, or
31
+ `await` it. That comes from Widget/LampWidgetSupport.swift, which Lamp writes: never edit it. It gives what the app
32
+ shared last, also while the app is closed, and nil until the app has run once: then show a short line asking to
33
+ open the app.
34
+ - Share a small value made for the widget, not everything, and declare its type on both sides.
35
+
36
+ A button or toggle in the widget changes the app's data through the app: in Widget/, an App Intent whose `perform()`
37
+ calls `await LampWidget.perform("addWater", 250)` (a name, and any Codable value or none) and returns `.result()`,
38
+ shown with `Button(intent: AddWater()) { … }`; in the app, at launch, `LampWidget.onAction { name, payload in … }`
39
+ does it (`payload.decode(Int.self)`) and shares what changed, and the widget redraws. It works with the app closed
40
+ too: the app does it when it next starts.
41
+
42
+ ## When the widget is all they asked for
43
+
44
+ When a widget is all the user asked for ("make me a countdown widget"), they get only the widget, with no app
45
+ window: make Sources/App.swift just `@main struct MainApp: App { var body: some Scene { LampWidgetOnly() } }`, with no
46
+ commands, delete Sources/ContentView.swift with delete_file, and put everything in the widget, which works out what it
47
+ shows by itself (the date, the web). Such an app has no window, no Dock icon and is never opened, so don't call
48
+ `look_at_app` or `use_app` for it.
49
+
50
+ Only when the widget has to show something an app must fetch or keep for it (the user's files, calendar or mail,
51
+ what they type in, an AI answer) does it get a real app, which shares that with `LampWidget.share` and lives in the
52
+ menu bar (`LampMenuBar`, with its Quit button; the menu-bar skill says how) unless the user asked for a window too.
53
+
54
+ ## What to tell the person
55
+
56
+ Lamp shows the user a card that says how to add the widget and when it's on their desktop, so never explain how to
57
+ add it, and never say you couldn't see it. When the request was for a widget, what you say once it's made is two
58
+ sentences at most, on what the widget shows: no list of sizes or options, no assumptions, no "it's ready", no
59
+ question at the end. A widget they placed stays through your changes and shows them by itself. To take the widget
60
+ away, delete the files in Widget/.
@@ -0,0 +1,8 @@
1
+ ---
2
+ name: maps
3
+ description: A real place from map data (OpenStreetMap) - a town to drive or walk through, a campus, a neighborhood, with its buildings, roads and shops. Read before fetching or drawing map data.
4
+ ---
5
+
6
+ # Real places from map data
7
+
8
+ A real place (a town to drive, a campus, a neighborhood) comes from OpenStreetMap. Fetch it from the Overpass API (overpass-api.de, else a mirror), one bounding-box query for everything in the box and what it's made of (`nwr(…); (._; >;); out;`: nodes too, since trees, shops and signals are often single points), waiting and trying again when it's busy; never OpenStreetMap's own editing API, which its rules keep from bulk downloads. Turn it, while building, into a compact file in Assets/ that the app reads (meters from a center point, footprints already triangulated), not raw OSM parsed at launch. Worth reading: each building's footprint, `height` or else `building:levels` (about 3.3 m a floor) or else a guess from `building` (house, garage, apartments, university…), `roof:shape`, `building:colour`, `roof:colour` and `building:material` (use them when they're there, and choose from the building's type only when they aren't), and `building:part` for landmarks' stepped parts; roads with `highway`, `width` or `lanes`, `oneway` and `name`; traffic signals, crossings, footpaths and trees; the ground: parks, gardens, pitches, grass, cemeteries (`leisure`, `landuse`), water and rivers (`natural=water`, `waterway`), woods (`natural=wood`, `landuse=forest`), car parks; shops and amenities with `name`, `opening_hours` and address. Large areas and buildings with courtyards are often relations (`type=multipolygon`), not closed ways: join their `outer` members' ways end to end into rings and cut out the `inner` ones, or the biggest parks, the river and many landmarks go missing. An area larger than a tile (a park, a river, a lake) is cut along the tile edges while building the map file, each piece clipped to its square and drawn by that tile, so it shows wherever the player is in it, not only near its center. In a 3D scene, stream the world by tile (the scene-3d skill's `scene.stream`), and show "© OpenStreetMap contributors" on screen.
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: menu-bar
3
+ description: A Mac app that lives in the menu bar (LampMenuBar) - a panel, a menu, or one thing the icon turns on and off, with its Settings and Quit, Lamp's wand, and how it stays within reach. Read before writing or changing a menu bar app or a menu bar icon.
4
+ ---
5
+
6
+ # A Mac app in the menu bar
7
+
8
+ Use `LampMenuBar` from LampSupport.swift as the app's scene, instead of `MenuBarExtra`:
9
+ `LampMenuBar("Focus Timer", systemImage: "timer") { PanelView() }`, or `LampMenuBar { PanelView() } label: { … }` for
10
+ an icon or text that changes, with `.commands { LampCommands() }` on it and a `Settings` scene beside it.
11
+
12
+ It gives the app an icon with a panel and no Dock icon, and keeps it within reach: it opens the panel as a normal
13
+ window when the icon is hidden (a full menu bar, the notch), shows the panel when the app is opened again, and puts
14
+ the app in the Dock while one of its windows is open. So never call `NSApp.setActivationPolicy` or add a window just
15
+ to make the app reachable.
16
+
17
+ ## The panel
18
+
19
+ - Such an app has no Dock icon and no menus, so the panel needs its own Settings button, which calls
20
+ `LampMenuBar.openSettings()` (never `SettingsLink` or `openSettings`: from a menu bar app those open the window
21
+ behind other apps, where it gets lost), and its own Quit button (`NSApp.terminate(nil)`).
22
+ - `LampMenuBar.close()` closes the panel after an action in it.
23
+ - Put `LampPanelWand()` beside the panel's own buttons, at the right of its header (or of its footer, beside Settings
24
+ and Quit, when the header has none), as a window has Lamp's wand in its title bar (without it, Lamp gives it a
25
+ strip of its own above the panel).
26
+ - Give the panel a fixed width, and hand it its model inside the braces (`{ PanelView().environmentObject(model) }`),
27
+ never with a modifier on the scene, which crashes the panel.
28
+ - Pass `dockIcon: true` only when the app also has a main window.
29
+
30
+ ## A menu, or a switch
31
+
32
+ - For a menu instead of a panel: `LampMenuBar(menu: "Clipboard", systemImage: "list.clipboard") { Button(…);
33
+ Toggle(…); Divider() }`, which adds Settings… and Quit itself (`settings: false` when there's no Settings scene).
34
+ - For one thing the app turns on and off: `LampMenuBar("Keep Awake", isOn: $model.awake, on: "cup.and.saucer.fill",
35
+ off: "cup.and.saucer") { more menu items }`, where a click flips it and a right-click shows the menu; keep that
36
+ state in the App (@StateObject or @State) so the icon follows it.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: more-apps
3
+ description: Whether a request is for one more app beside the ones the project has, or a change to an app it has - "never mind, make it a timer instead" versus "also an Android app" - asking the person before adding one, why a second app of a kind the project has (two Mac apps) can't be added yet, and how to call make_app_for for each (`app` or `another`). Read before adding an app to a project that has one.
4
+ ---
5
+
6
+ # One more app, or a change to the one the project has
7
+
8
+ A project that has an app (made, or still waiting to be made) never gets another by accident: `make_app_for` refuses a
9
+ call that names neither `app` nor `another`. Which one you give is the person's choice, read from what they asked.
10
+
11
+ ## A change to the app they have
12
+
13
+ Most requests are this. The person changes their mind or wants something else in its place:
14
+
15
+ - "Actually never mind, make it a pomodoro timer instead."
16
+ - "Make it do X instead." "Turn it into a game." "Can it be for my iPhone too?"
17
+
18
+ Change the app the project has. When only what it does changes, change its code: no `make_app_for` at all. When what it's
19
+ made for changes (other devices, web or native), call `make_app_for` with its folder in `app` ("." for the app in the
20
+ project's own folder). It keeps its folder, its saved data and its place among the project's apps. Never add an app for a
21
+ change of mind, and never take the old one away to make room: the person didn't ask for either.
22
+
23
+ ## One more app, of another kind: ask first
24
+
25
+ A project can have one more app beside the ones it has only when it's of another kind: an Android app beside a Mac app,
26
+ a TV app beside an iPhone app. Two apps of one kind (two Mac apps, two iPhone apps) can't
27
+ be in one project yet, and `make_app_for` refuses one, nothing changed; a device's own app (a Roku's) is one per project.
28
+
29
+ When the person seems to want another app of a kind the project doesn't have ("also make an Android app for my phone",
30
+ "a web game to go with it"), ask them before calling `make_app_for` or writing anything, with `ask`: one short question,
31
+ two answers in their words. Adding an app is theirs to choose, so ask even when the request sounds clear; it costs them
32
+ one click.
33
+
34
+ - Question: "An Android app as well, or make this one Android?"
35
+ - Answers: "A second app" (one more app beside the one they have) and "Change this one" (the app they have, changed).
36
+
37
+ End your turn after asking: their answer is the next message. Don't ask again when the message is already their answer
38
+ to that question.
39
+
40
+ - A second app: `make_app_for` with `another: true` and the devices and make of the new app. It goes in a folder of its
41
+ own, with its own name, id and data, and the project's other apps stay as they are.
42
+ - A change: the app they have, as above.
43
+ - Their own words instead: follow those.
44
+
45
+ ## Another app of the same kind
46
+
47
+ When they ask for another app of a kind the project already has ("I want a second Mac app, a journal" in a project with a
48
+ Mac app), don't offer a second app: it can't be added yet. Tell them so in a sentence, and offer what can be done
49
+ with `ask`: change the app they have into it, or make it a separate app of its own (from Lamp's desk). Never add it
50
+ by changing what it's made for so it slips in as another kind, unless that's what they asked for: another make than the
51
+ defaults give (the web-or-native skill), only to get around this limit, is never the answer.
52
+
53
+ Never answer the question for them, and never add an app for a change of mind.
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: phone-controllers
3
+ description: What to weigh when phones are to be controllers or a second screen for a game or app - whose phones, who can host them, a page or an app on the phones, and what Lamp can't do yet. Read whenever someone wants to play or steer something with their phone.
4
+ ---
5
+
6
+ # Phones as controllers: what to consider
7
+
8
+ "A game I can control with my phone" can be made several ways. Before building, think through these, and ask the
9
+ person only what you can't tell from the request (one short line, about people and devices).
10
+
11
+ `make_app_for`'s table says what each device runs; it doesn't yet say which apps can take phones, because that
12
+ depends on how an app is made and run, not on the device alone. What follows is that account.
13
+
14
+ ## Whose phones?
15
+
16
+ - **Several people's** (family, friends, a class): each phone has to join with nothing to install. That's a page for
17
+ phones: they scan a QR code on the screen and play in their browser. The phone-pages skill says how to build it.
18
+ - **Only the person's own phone**: on an iPhone, an app of the project's own, made natively, is the controller: it has
19
+ the phone's own feel, hardware and haptics, and keeps its data, and joins as a player with `LampController` over
20
+ `LampWish`. Installing it goes the way the table says for that phone. An Android app has no `LampController`, so it
21
+ can't join a game as a player: for game controls on an Android phone, native is out of reach and a page is the
22
+ answer. A native Android app still suits plain messages to the TV app through `LampWish` (a few commands, a
23
+ photo sent). A page works for an iPhone too, when they ask for one.
24
+
25
+ ## What hosts phones today
26
+
27
+ Phones join in two separate ways.
28
+
29
+ A phone's browser, joined by a QR code, needs a phone page (`Phone/index.html` in the app's own folder, beside its
30
+ `Web/`: the phone-pages skill says where) and a page on the screen that uses lamp.js's `Lamp.controllers`. Two kinds
31
+ of app have both:
32
+
33
+ - a game on Lamp's game runtime (`make_app_for` with `kind` "game");
34
+ - a TV app's page: while it's open on a Samsung or LG TV or in its TV preview on this Mac.
35
+
36
+ Who serves the phone page and runs the link phones join is the game's choice, `Lamp.controllers.start({ host })`
37
+ (the phone-pages skill):
38
+
39
+ - Game-owned hosting (`'game'`) runs with the game and needs no Lamp. The game has it on the Mac, on an iPhone or iPad
40
+ while it's in front, on an LG TV from webOS 5 on, where Lamp packages a service with the game, and on the Xbox,
41
+ where the game's own host runs it.
42
+ - Lamp hosting (`'lamp'`) needs Lamp open and the Mac reachable. Lamp has it for the TV preview, a Samsung or LG TV and
43
+ the Xbox.
44
+ - Device networking and store rules can affect either one.
45
+
46
+ They're options, not an order, and another approach is fine. A host that isn't there, or fails, is said in
47
+ `onError`; the game never moves to the other one by itself. `start()` with no host keeps where each device ran before.
48
+
49
+ An iPhone app of the project's own needs no browser page: it joins the TV app's game as a player with `LampController`
50
+ over `LampWish`. An Android app has no `LampController` and doesn't join as a player. Every app of the project's talks to
51
+ the others through `LampWish` (messages, shared values, files) on whichever devices they're on (the wish-links skill).
52
+
53
+ On an iPhone or iPad the game's own phones play only while the game is in front: when the person leaves it, every
54
+ phone is let go, and once they come back the game shows a new code to scan (`Lamp.controllers.onLink` hears it).
55
+
56
+ Neither host covers a game played on Android, a page shown by Lamp's other hosts, or a native app yet. Say so plainly
57
+ when the person asks for phones there.
58
+
59
+ ## A page or an app on the phones?
60
+
61
+ For the person's own iPhone, an app of the project's on it, made natively. For game controls on an Android phone, a page,
62
+ since a native Android app can't join as a player.
63
+ For several people's phones joining one game or TV app, a page: nothing to install, and any phone on the Wi‑Fi joins (that's
64
+ one app shared across devices, the case where web-or-native chooses web). The web-or-native skill has the rest of that
65
+ choice.
66
+
67
+ ## Away from home
68
+
69
+ Phones reach the phone page on the same Wi‑Fi, whichever host serves it. Friends in other
70
+ homes can't join through it: say so if that's what they want. Apps of the project's that talk through `LampWish` work
71
+ by its own rules (the wish-links skill).
72
+
73
+ ## Building it
74
+
75
+ In a game, the game-ui skill ("With phones") settles what the shared display and each phone show in each phase, who
76
+ steers a menu, and what this player does on the phone. Once you've chosen, open the phone-pages skill: the page in the app's own Phone/, `LampController` on the phone and
77
+ `Lamp.controllers` on the screen, files, tilt, second screens, how a game's controls are held, how views and moves
78
+ go between the game and the phone, and how to see and press the page yourself. A game on Lamp's runtime reads phones' buttons each frame from `f.phones` (the game
79
+ skill), which keeps a quick press that `onButton` alone can lose between frames.
@@ -0,0 +1,173 @@
1
+ ---
2
+ name: phone-pages
3
+ description: How to build a page for phones on the same Wi-Fi - phones as controllers (buttons, sticks, a wheel, a buzzer, a game's own interaction, how views and moves go between game and phone), a second screen joined by a QR code, or sending the TV a file (a photo, a game, a song). Read before writing Phone/ or using Lamp.controllers or Lamp.phonePage.
4
+ ---
5
+
6
+ # Phones as controllers and second screens
7
+
8
+ The phone's page goes in the app's own `Phone/` folder, beside its `Web/`: `index.html` and the files beside it, loaded with relative paths. In an app shared with the person, the phone's browser lets the page load only its own files, its link to the game and the sites its review named: keep everything such a page uses (scripts, styles, fonts, pictures, sounds) in `Phone/`. The app is a game on Lamp's runtime or a TV app, and its folder is the one `make_app_for` returned: an app at the project's root has `Phone/index.html` beside `Web/index.html`, and one in a folder of its own (`TV/`, `Game/`) has `TV/Phone/index.html` beside `TV/Web/index.html`. Lamp serves only the app's own `Phone/`, so a page anywhere else (a `Phone/` at the project's root beside `TV/`) is never served and its link answers "not found". Write the path from the project's folder in every file tool call: a `cd` in a shell command doesn't change the folder later file tools write in. It runs in the phone's own modern browser, so it isn't held to the TV's 2019 syntax. The page is served, and the phones' input and files go to the screen over the home Wi-Fi, by the host the game chooses as it starts (below): the game itself or Lamp on the Mac. Nothing secret goes in `Phone/`: anyone on the Wi-Fi with its address can load it. Whatever carries the phones, keep what Lamp's hosts keep: a link a phone opens is an invitation for anyone who has it, so make it short-lived and never put the app's own keys or the person's data in it, the page or its messages; let in only the game's own page and the phones it invited; and send nothing past the home network unless the person asked for that. Phones need nothing in capabilities.json: Lamp gives the system its reason for them. A `localNetwork` reason there says the app reaches the person's devices, so pressing anything in it with `use_app` needs a device they allowed (the device-control skill).
9
+
10
+ ## Controllers
11
+
12
+ On the phone, the page loads `lamp-controller.js`, which Lamp serves beside it (don't write one): `<script src="lamp-controller.js"></script>`.
13
+
14
+ ```js
15
+ var pad = LampController.connect({
16
+ onPlayer: function (n) { }, // this phone's player number (1, 2, ...)
17
+ onMessage: function (data) { }, // what the TV app sent this phone, or every phone
18
+ onState: function (state) { }, // 'connecting', 'connected', 'waiting' (the TV app isn't there), 'ended', 'full'
19
+ busy: function () { return false; }, // true while opening again would lose something (a drawing, a form)
20
+ onUpdate: function (apply) { } // leave it out unless the page must choose: call apply() to open the newer page
21
+ });
22
+ pad.button('jump', true); pad.button('jump', false); // a button held, then let go, named for what it does
23
+ pad.axis('steer', x, y); // a stick, wheel or slider, each from -1 to 1
24
+ pad.send({ ready: true }); // JSON to the TV app, 16 KB at most
25
+ ```
26
+
27
+ A page open on a phone takes what you save to Phone/ by itself where the host can, a few seconds later: it opens again as the same player once no button is held, no file is on its way, nothing is being typed and `busy` says false. So keep a form's or a drawing's work behind `busy`, or give `onUpdate` a button when only the person should choose. Phones and the TV don't switch at the same moment, so a change of what they send each other should still read the other side's old messages.
28
+
29
+ Make each control big enough for a thumb, show the player's number and the state (say plainly when the TV app isn't there or the game has ended), and send a button's press and its release, so the TV can tell held from tapped. The number comes from the TV app once it's there (`onPlayer`), so show the state until then. `onState` runs during `connect()` itself, before it returns, so set up everything it touches first: a first draw that throws there stops the page's script and leaves the phone on its loading text.
30
+
31
+ `pad.button`, `pad.axis` and `pad.send` return false when nothing was sent: show that state, never a press that went nowhere.
32
+
33
+ ### How a game's controller is held
34
+
35
+ The game-ui skill ("With phones") settles what the controller is, and that settles how it's held. A two-thumb page is made for landscape: movement on the left, the main action on the right, and the player, the link and Back quiet in the middle or along the top. Compose those zones for the game and its verbs; a portrait layout stretched sideways isn't this. A page built around one big interaction (a lock, a dial, a hand of cards) and a page that isn't game controls (photos, files, a scoreboard) stay whichever way suits them, with the same safe areas and the same care when the phone turns.
36
+
37
+ - Lay it out with `viewport-fit=cover` in the viewport tag, `env(safe-area-inset-*)` around the edges and `100dvh` for the height, so a notch and the browser's bars don't sit on a control.
38
+ - Nothing forces a phone sideways. `screen.orientation.lock` works in few browsers and usually only full screen: try it after a tap if you like, handle its failure, and make the page right without it. Never rotate the page with CSS.
39
+ - Joining and typing a name may stay upright, and the keyboard changes the viewport's shape: decide what `@media (orientation: …)` shows from the game's phase too, so a keyboard never hides the name field behind "turn your phone".
40
+ - A two-thumb page held upright during play: keep the player and the link on screen, show a themed "Turn your phone sideways", take no play gestures, and offer "Use upright" with a compact layout for someone who can't rotate. Keep Back reachable, and never pause the party for one phone turning.
41
+ - If the phone turns during a press, end any gesture (below), send every held button's release and zero every active axis, drop the page's own pointer capture and gesture state, and ask for a fresh press. The page keeps track of what's held; never close the link to clear it. Turning back restores the phase as it was, with no new join and no reset.
42
+
43
+ ```js
44
+ var held = {};
45
+ function press(name, down) { if (down) held[name] = true; else delete held[name]; pad.button(name, down); }
46
+ function letGo() {
47
+ Object.keys(held).forEach(function (name) { press(name, false); });
48
+ pad.axis('steer', 0, 0); // every axis this page moves
49
+ }
50
+ matchMedia('(orientation: landscape)').addEventListener('change', letGo);
51
+ ```
52
+
53
+ ### Views and moves
54
+
55
+ The game owns what's true; a phone draws what it's told and asks for moves. There's no second state machine on the phone.
56
+
57
+ - **Views.** Derive each player's view from the game's state in one function, and send it to that player alone (`send(player, view)`, never player 0 for anything private) whenever what it holds changes, not only when the phase does: a wrong attempt changes the view with no change of phase. It goes out on `onJoin` too, which also runs for a phone coming back and for a page that opened again, and for phones already joined when the code runs again: `onJoin` puts that in the moves' queue, so the view that lets a phone act again answers every move it sent before. The phone keeps nothing it can't get back from its next view. A player with no part in the current view, like one back from a dropped link, is shown that and when they're next in, never an empty screen.
58
+ - **Turns.** Each view carries the phase and a `turn` the game moves on whenever an old screen's move would no longer mean the same thing (a new round, a new turn). A move names the `turn` it was made on, and an `id`, since a `turn` can't tell two moves in one turn apart: one more than the `answer.id` in the view it was made on (below), so ids come from the game and survive the page opening again.
59
+ - **Moves.** Send the finished move as one bounded message: `pad.send({ move: 'try', id: id, turn: view.turn, path: path })`. `pad.axis` is for live movement only: an axis is dropped when the game is behind and late ones are thrown away, so never build a result from them. Collect a path on the phone and send it when it ends.
60
+ - **The game decides.** `f.phones` holds buttons only; axes and messages come by `onAxis` and `onMessage`, between frames, so the game keeps its own queue and empties it in `frame`, never a flag `frame` clears. It drops a move from another phase or `turn`, whose phone has already moved on, and takes one with an `id` no newer than the player's last answer as a repeat, which changes nothing and only sends the view again. For any other move it checks the player and the move's size and shape, accepts or rejects it, and keeps that for the player. Every view carries that as `answer: { id, ok }`, `{ id: 0 }` before the first.
61
+ - **One move at a time.** After sending, a phone takes no new move until a view's `answer.id` reaches it or a view has another phase or `turn`: views go out for other reasons too, and `send` returning true only means it went out. There's no timer that offers a fresh move, because a move that's late can still land, and two ids would count twice. A message can be dropped when the game is far behind, so a game whose turn can sit forever may send the same move again, same `id`, after a few seconds. A phone that loses its link forgets a waiting move and never sends it again after a reconnect; the view it comes back to says what happened.
62
+ - **Input needs a current view.** A view belongs to the link it came on: take input only once one has arrived, and stop when `onState` leaves `connected`, until the view queued by `onJoin` comes on the new link.
63
+ - **A gesture that's interrupted is no move.** Track the finger's `pointerId` and capture it. End the gesture, send nothing and clear what it drew on that finger's `pointercancel` or `lostpointercapture`, when the page is hidden (`visibilitychange`), when the phone turns, when `onState` leaves `connected`, and when a view arrives with another phase or `turn`. Only that finger's `pointerup` in the same `turn` submits, and it ends the gesture first, so the `lostpointercapture` that follows a normal release finds nothing to cancel. Keep `busy` true during a gesture so a newer page waits for it.
64
+
65
+ ```js
66
+ var view = null, live = false, path = null, finger = null, waiting = null;
67
+ function cancel() { path = null; finger = null; draw(); }
68
+ var pad = LampController.connect({
69
+ onMessage: function (next) {
70
+ var moved = view && (next.turn !== view.turn || next.phase !== view.phase);
71
+ if (moved) { path = null; finger = null; }
72
+ if (moved || next.answer.id >= waiting) waiting = null; // any other view isn't an answer
73
+ view = next; live = true; draw();
74
+ },
75
+ onState: function (state) {
76
+ if (state !== 'connected') { live = false; path = null; finger = null; waiting = null; }
77
+ draw();
78
+ },
79
+ busy: function () { return !!path; }
80
+ });
81
+ lock.addEventListener('pointerdown', function (event) {
82
+ if (!live || path || waiting !== null) return;
83
+ finger = event.pointerId; lock.setPointerCapture(finger); path = []; draw();
84
+ });
85
+ lock.addEventListener('pointerup', function (event) { if (event.pointerId === finger) finish(); });
86
+ ['pointercancel', 'lostpointercapture'].forEach(function (name) {
87
+ lock.addEventListener(name, function (event) { if (event.pointerId === finger) cancel(); });
88
+ });
89
+ document.addEventListener('visibilitychange', function () { if (document.hidden) cancel(); });
90
+ matchMedia('(orientation: landscape)').addEventListener('change', cancel);
91
+ function finish() { // the finger lifted, or Submit
92
+ if (live && path) {
93
+ var id = view.answer.id + 1;
94
+ if (pad.send({ move: 'try', id: id, turn: view.turn, path: path })) waiting = id;
95
+ }
96
+ path = null; finger = null; draw();
97
+ }
98
+
99
+ // In the game: moves wait for the frame, and the state decides.
100
+ var moves = [];
101
+ Lamp.controllers.onMessage(function (player, data) { moves.push({ player: player, data: data }); });
102
+ Lamp.controllers.onJoin(function (player) { moves.push({ player: player, joined: true }); });
103
+ // in frame(f), the only place views are sent: for each of moves.splice(0): drop an old turn's; for a new id, check it,
104
+ // change the state and keep { id, ok } for that player's views; then sendView for whoever's view changed, for a
105
+ // repeat and for joined
106
+ ```
107
+
108
+ ### Seeing the page
109
+
110
+ Lamp can't open or press this page itself: only the person's own phones join the game. Check it by reading it against
111
+ the game's messages (what each view needs, what each press sends, the link lost and back, rotation with a control held),
112
+ say plainly that you haven't seen it on a phone, and ask the person to try the whole journey on theirs: joining, the
113
+ menu, play, a move the game rejects, results, the link lost and back, and rotation with a control or a gesture held.
114
+
115
+ On the TV, in `Web/`, `Lamp.controllers` (lamp.js's comment) runs the game. It starts with a host:
116
+
117
+ - `Lamp.controllers.start({ host: 'game' })`: the game serves the page and runs the link itself, with no Lamp: on the Mac, an iPhone or iPad while it's in front, an LG TV whose package carries the game's service (webOS 5 on), and the Xbox. Lamp's TV preview has no game host.
118
+ - `Lamp.controllers.start({ host: 'lamp' })`: Lamp serves the page and runs the link, while Lamp is open and the Mac is reachable: in the TV preview, on a Samsung or LG TV and on the Xbox.
119
+ - `Lamp.controllers.start()`: where it ran before either existed (the game itself on the Mac, iPhone and iPad; Lamp elsewhere).
120
+
121
+ A host that isn't there, or fails, says so in `onError` and is tried again; the other one is never used instead. `stop()` ends the session the chosen host runs, and a later `start` may choose again. Then `onLink(fn(url))` for the address phones open, to show as a QR code (below; it changes every few minutes, and `fn` is called again each time), `onJoin`/`onLeave(fn(player))`, `onButton(fn(player, name, down))`, `onAxis(fn(player, name, x, y))`, `onMessage(fn(player, data))`, `onError(fn(message))`, `send(player, data)` (player 0 for every phone; 16 KB of JSON at most), `isHeld(player, name)`, `players()` and `stop()`. A phone that leaves or drops has every button it held let go before `onLeave`, and movement that arrives late is dropped, so the game never acts on a stale stick. A game on Lamp's runtime reads buttons each frame from `f.phones` rather than `onButton` (the game skill).
122
+
123
+ The session belongs to the page, not to one run of the game's code. When Lamp runs a game's code again in place for a change, phones stay joined with their numbers, so the code sets its `on…` callbacks as it starts and calls `start` as usual (with the same host it's already running, it changes nothing), and nothing stops or restarts the phones; a `stop()` in `dispose` is ignored. Before the new code's first frame, `onLeave` and `onJoin` hear who left and who is here, so `onJoin` is written to be called again for a player the game already has: the game skill's snapshot rule says how slots come back. The phone keeps its page and number throughout and sees no change.
124
+
125
+ ### The join code
126
+
127
+ Draw the code with `LampQR`, which lamp.js has (its comment says how): never write a QR encoder or load one. A join link carries a signed credential, so it's long (about 170 characters, more with a long name or host); `LampQR` fits any length a link has.
128
+
129
+ ```js
130
+ var code = document.getElementById('join-code'); // a <canvas> in the join card
131
+ Lamp.controllers.onLink(function (url) { // before start(), so the first link is drawn too
132
+ try { LampQR.draw(code, url, { size: 240 }); joinNote.textContent = 'Scan to play'; }
133
+ catch (e) { joinNote.textContent = 'Couldn\'t draw the code: ' + e.message; }
134
+ });
135
+ Lamp.controllers.onError(function (message) { joinNote.textContent = message; });
136
+ Lamp.controllers.start();
137
+ ```
138
+
139
+ In a game, the join card is a screen of its own, not part of a title (the game-ui skill has the flow, and what the shared display and each phone show in each phase): show it at once when the player goes to join, or from setup or pause to add players, and a game played only with phones may open on it. While it's up it says when the game is getting ready for phones (until the first link), when phones can't join and when it's trying again. Keep the session running behind it: hiding the card never calls `stop()`, drops a player or starts again. While it's hidden, keep the newest `onLink` address and the newest error rather than a picture of an old code, and draw the card from those when it opens, finding its elements again, since a change to the code may have made them anew. Register the handlers before `start()` in every case, and keep the links short-lived. A page that isn't a game (a second screen, a file sent to the TV) may show its code from the start. Draw into the same canvas each time `onLink` calls again. A code that couldn't be drawn and phones that can't join (`start()` rejects, `onError`) each say so in the card; neither hides it as if the game had no phones. In a game drawn on a canvas (three.js, Phaser), put the join card in HTML over it, or draw `LampQR.matrix(url)` (its `size` and `dark(x, y)`) into the scene yourself, with a light border four modules wide.
140
+
141
+ ## Files
142
+
143
+ One message, as the JSON that goes out, is at most 16 KB (`LampController.messageLimit`, `Lamp.controllers.messageLimit`), either way. A bigger one isn't sent: `send` returns false, and the TV app's log (and its `onError`) says so with its size. `send` also returns false while the other side isn't there.
144
+
145
+ Anything bigger (a photo, a game for the TV to play, a song, a document) is a file, sent in pieces with its own progress, so buttons pressed meanwhile still arrive at once. Never cut it into messages yourself, as text or base64.
146
+
147
+ ```js
148
+ // On the phone: a File from <input type="file">, a Blob, an ArrayBuffer, bytes or text, up to 64 MB.
149
+ var sending = pad.sendFile(input.files[0]); // or pad.sendFile(bytes, { name: 'level.json', type: 'application/json' })
150
+ sending.onProgress(function (sent, size) { }); // show it
151
+ sending.done.then(function () { }, function (error) { /* error.message: say it */ });
152
+ sending.cancel();
153
+
154
+ // On the TV, in Web/:
155
+ Lamp.controllers.onFile(function (player, file) { // file.name, file.type, file.size
156
+ file.onProgress(function (received, size) { });
157
+ file.done.then(function (arrayBuffer) { }, function (error) { });
158
+ });
159
+ ```
160
+
161
+ The TV sends a phone a file the same way, with `Lamp.controllers.sendFile(player, data, { name, type })`, which the phone hears in `onFile` (passed to `LampController.connect`). A file whose player leaves, or whose link drops, ends with an error: say so and let the person send it again. Keep a TV's memory in mind: read what arrived and let it go rather than keeping many large files.
162
+
163
+ ## Tilt
164
+
165
+ The page is plain http, and phones give their motion sensors only to https pages. So a game's controller is a touch interaction that's usable without tilt, whatever shape the game-ui skill's design gave it. Offer tilt only where `LampController.canTilt()` says so, from a tap (a Start button), since the browser asks the person first: `LampController.tilt(pad).then(...).catch(...)` then sends the phone's tilt as axis `'tilt'` (x: left -1 to right 1, y: away -1 to toward 1). Where it can't, the game must still be fully playable by touch. The wake lock and `navigator.vibrate` are extras in the same way: many phones won't give them to this page, so try them, handle their failure, and let nothing depend on them.
166
+
167
+ ## The project's own apps
168
+
169
+ A phone's page is not one of the project's apps. When the project has an iPhone, Mac or Android app beside the TV app, those apps and the TV page see each other and talk through `LampWish` (`Lamp.wish` in lamp.js, `LampWish` in LampSupport): who is open now, and messages between them. `Lamp.controllers` and `LampController` are for steering the TV (buttons, sticks, files to the TV); for anything else between the project's apps, use `LampWish`, whose comment in lamp.js and LampSupport says how.
170
+
171
+ ## A second screen
172
+
173
+ For a page that shows something beside the TV rather than steering it (a hand of cards, a scoreboard, a buzzer that needs no game), the TV page draws a QR code of `Lamp.phonePage(hash)` with `LampQR.draw`, the page's address with `#hash` after it, inside `Lamp.onPhonePage(fn)`: it's called at once when there's an address and again whenever it moves, so redraw the code there. It's null when the app has no `Phone/index.html`. `Lamp.phonePage` and `Lamp.onPhonePage` are a TV app's page's only: a game on Lamp's runtime draws its QR code of the address `Lamp.controllers.onLink` gives (the join code, above), so every phone that opens it joins as a player, and what each phone shows is what the game sends it (`send`). What the phone and the TV say to each other goes through `Lamp.controllers` and `LampController` (`send` and `onMessage`, `sendFile` and `onFile`).
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: roku-developer-mode
3
+ description: How Lamp walks the person through turning on developer mode on their Roku the way Roku documents it - pressing the remote's secret keys over the Roku's own control protocol, then waiting while the person enables the installer, accepts the license and sets a developer password, and the Roku restarts. Lamp's Roku setup follows the steps below when the person clicks Do It for Me.
4
+ setup-for: roku
5
+ setup-step: developer-mode
6
+ ---
7
+
8
+ # Turning on developer mode on a Roku
9
+
10
+ A Roku takes the person's own channels once its developer mode is on. Roku documents how
11
+ (https://developer.roku.com/docs/developer-program/getting-started/developer-setup.md): press Home three times, Up
12
+ twice, then Right, Left, Right, Left, Right on the remote; the developer screen opens; enable the installer, accept the
13
+ Developer Tools License Agreement, enter a password, and the Roku reboots.
14
+
15
+ Lamp can press those keys for the person: Roku's External Control Protocol takes `POST /keypress/<key>` on port 8060
16
+ (https://developer.roku.com/docs/developer-program/debugging/external-control-api.md), once Settings > System >
17
+ Advanced system settings > Control by mobile apps is Enabled, which is the Roku setup's step before this one. The
18
+ license and the password are the person's, on the Roku: Lamp never presses them.
19
+
20
+ What Lamp sees: that the Roku answers on port 8060, that it went away and came back (the reboot), and
21
+ `developer-enabled` in `/query/device-info` reading `true`. Nothing else is said done.
22
+
23
+ ## What Lamp never does
24
+
25
+ - Accept the license or choose the password for the person, or press anything on those screens.
26
+ - Press the keys again after a failure part way: it can't tell which reached the Roku, so the person finishes this
27
+ step on the remote instead.
28
+ - Press the keys when `developer-enabled` already reads `true`.
29
+
30
+ ## Not yet checked on a real Roku
31
+
32
+ - The whole guide. Every request and value comes from Roku's documents and Lamp's Roku integration, whose own
33
+ developer-mode step presses the same keys the same way.
34
+ - Whether a Roku that already had developer mode on and was set up again goes straight to the password.
35
+
36
+ ## The steps
37
+
38
+ Lamp's setup reads this block and follows it in order; the frontmatter says it does the Roku setup's
39
+ `developer-mode` step, on any Roku. `{name}` is the Roku's name. The connection is plain HTTP, as the Roku
40
+ integration's own steps are.
41
+
42
+ ```lamp-setup
43
+ {
44
+ "connection": "http",
45
+ "offer": "Lamp presses the Roku's secret keys; you accept the license and set a password.",
46
+ "reach": [
47
+ { "http": { "port": 8060, "path": "/query/device-info" } }
48
+ ],
49
+ "steps": [
50
+ {
51
+ "do": "connect",
52
+ "doing": "Checking {name} answers…",
53
+ "done": "{name} answers"
54
+ },
55
+ {
56
+ "do": "request",
57
+ "run": [
58
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Home" } },
59
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Home" } },
60
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Home" } },
61
+ { "wait": 3 },
62
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Up" } },
63
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Up" } },
64
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Right" } },
65
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Left" } },
66
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Right" } },
67
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Left" } },
68
+ { "http": { "method": "POST", "port": 8060, "path": "/keypress/Right" } }
69
+ ],
70
+ "unless": [
71
+ { "http": { "port": 8060, "path": "/query/device-info" }, "xml": "developer-enabled", "equals": "true" }
72
+ ],
73
+ "doing": "Pressing the keys that open the developer screen on {name}…",
74
+ "done": "Pressed the keys that open the developer screen on {name}",
75
+ "failed": "Lamp couldn't finish pressing the keys. On the Roku's remote, press Home three times, then Up, Up, Right, Left, Right, Left, Right."
76
+ },
77
+ {
78
+ "do": "rejoin",
79
+ "ask": "On the Roku, choose Enable installer and restart, accept the license, then set a developer password. The Roku restarts; Lamp carries on once it's back.",
80
+ "button": "It Didn't Restart",
81
+ "unless": [
82
+ { "http": { "port": 8060, "path": "/query/device-info" }, "xml": "developer-enabled", "equals": "true" }
83
+ ],
84
+ "link": {
85
+ "title": "Roku's Developer Setup",
86
+ "url": "https://developer.roku.com/docs/developer-program/getting-started/developer-setup.md"
87
+ },
88
+ "done": "{name} is back on"
89
+ },
90
+ {
91
+ "do": "wait",
92
+ "until": [
93
+ { "http": { "port": 8060, "path": "/query/device-info" }, "xml": "developer-enabled", "equals": "true" },
94
+ { "tcp": 80 }
95
+ ],
96
+ "every": 3,
97
+ "doing": "Waiting for developer mode…",
98
+ "done": "Developer mode is on"
99
+ },
100
+ {
101
+ "do": "handoff",
102
+ "ask": "Type the developer password you just set on the Roku."
103
+ }
104
+ ]
105
+ }
106
+ ```
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: scene-3d
3
+ description: 3D in a Mac app made natively, in Swift (RealityKit through LampSceneView) - a world to move through, a room, a thing to turn over and handle, a toy, or a 3D game the person asked to be native, and RealityKit's own physics for things that fall, roll, stack and collide. A 3D game is made web by default (the game and 3d-game skills). Read before writing or changing 3D in Swift on the Mac.
4
+ ---
5
+
6
+ # 3D scenes
7
+
8
+ This is 3D in a Mac app made natively. A 3D game is made web by default, on the Mac as elsewhere (the game and
9
+ 3d-game skills); it's made here only when the person asked for a native game, or it's a Mac app already made in Swift.
10
+
11
+ 3D scenes (a world to move through, a room, a thing to turn over and handle): RealityKit through LampSceneView, from Sources/LampScene.swift, which Lamp adds to an app whose code imports RealityKit (the app then needs macOS 15). `LampSceneView(sky:camera:props:build:update:)`: sky `.day`, `.sunset`, `.overcast`, `.night`, `.studio`; camera `.orbit(target:distance:)`, `.chase("entity name")`, `.firstPerson()`, `.fixed(position:lookAt:)` or `.manual`; `build` adds entities to `scene.root`; `update(scene, dt)` runs every frame, with `scene.isDown(.w)` for keys. In a file that imports RealityKit, SwiftUI's `Scene` must be written `SwiftUI.Scene`.
12
+
13
+ Things are made in code, in meters, from LampMesh (`box(size, corner:)`, `sphere`, `cylinder`, `cone`, `lathe([[radius, height], …])` for anything round, `extrude(path, depth:, chamfer:)`, `sweep(path, along:)`, `tube(along:radius:)`, `plane(width:depth:tile:)`, `text`) and LampMaterial (`metal`, `chrome`, `brushed`, `plastic`, `rubber`, `glass`, `paint`, `wood`, `fabric`, `ceramic`, `concrete`, `asphalt`, `brick`, `tiles`, `grass`, `glow`). A prop is a function returning one Entity of named parts at real size; the parts that move are `lampPress { }`, `lampTurn(axis:range:)`, `lampSlide(axis:range:)` and `lampGrab()`; `lampPhysics(.dynamic)` or `.static` for falling and knocking; `lampShadow()` under anything standing on the ground. Many copies of one thing go in one `LampScene.copies(of:at:)`. A world bigger than a few hundred meters (a town, a map, a landscape) is streamed, never built whole at launch: `scene.stream(tile: 100, radius: 400, around: { car.position }) { tile in … }` returns what's drawn on one tile (share things out with `tile.contains`), made as it comes into reach, by a named function (`{ tile in World.tile(tile) }`) so a change to it shows in the open app (anything else the app draws itself and should redraw after a change goes in LampSceneView's `onLiveChange`). A change that reshapes the view holding the LampSceneView gives it a fresh scene while the app's own objects carry on, so its `build` runs again on the same game: make `build` start clean (empty the lists, physics bodies and handles it fills, or make them anew) rather than add to what the last build left; what the game needs everywhere (collisions, routes, the map's data) is made once, outside it.
14
+
15
+ Keep it smooth: a frame has about 16 ms, and anything the app does while it's open (a frame's update, a tile, a prop that appears in play, a level loading) takes from it, so a slow piece is a stutter. Make each mesh, material, texture and piece of text once and reuse it (`copies` for many of one thing, one text mesh per distinct word), never the same thing again per place; turn heavy data (a map, a level) into a compact file in Assets/ while building, not at launch; keep per-frame work to what moves. A streamed tile should take a few milliseconds: the log names slower ones. When a tile has much to work out (a town's buildings and roads from map data), split it so that work leaves the main thread: `scene.stream(tile:radius:around:, prepare: { World.plan($0) }, make: { World.tile($0, $1) })`, where `plan` returns a `Sendable` struct of what's on the tile (its shapes as filled `LampMeshBuilder`s, positions, colors) and runs on other cores, several tiles at once, touching no entity, material or state the app changes, and `make` turns it into entities on the main thread with `LampMesh.make(builders)` and shared materials, in a millisecond or two.
16
+
17
+ Physics is RealityKit's own; nothing else is added for it. Most scenes need none: a thing moved by the app's own rules (a car along a road, a door that swings when clicked) is moved in `update`, and what it touches is tested there (distances, bounds). Use physics when things should behave like things: a stack that topples, balls that roll and knock into each other, something dropped, thrown or knocked over. `lampPhysics(.dynamic, mass:bounce:friction:)` makes a prop fall and be knocked about and `.static` what it lands on, from a `PhysicsBodyComponent` and a `CollisionComponent`. Its collision shape comes from its meshes unless the entity already has one, and for anything that moves it should: set `CollisionComponent(shapes: [.generateBox(size:)])` (or `.generateSphere(radius:)`, `.generateCapsule(height:radius:)`, several for a shape made of parts, `ShapeResource.generateConvex(from:)` for an odd one) before `lampPhysics`, never a detailed mesh. A body is `.dynamic` (moved only by physics: push it with `applyLinearImpulse(_:relativeTo:)` or `addForce(_:relativeTo:)`, never by setting its position each frame), `.static`, or `.kinematic` (moved by the app, pushing dynamic bodies without being pushed: a tilting board, a moving platform; give it a `PhysicsMotionComponent` velocity or move it in `update`). A fast small thing gets `isContinuousCollisionDetectionEnabled` on its body so it doesn't pass through thin walls. A player who walks, climbs steps and stands on slopes is a `CharacterControllerComponent(radius:height:skinWidth:slopeLimit:stepLimit:)` moved each frame with `moveCharacter(by:deltaTime:relativeTo:)`, gravity added by the app, `CharacterControllerStateComponent`'s `isOnGround` before a jump. Hinges, sliders, ball joints and welds are `PhysicsRevoluteJoint`, `PhysicsPrismaticJoint`, `PhysicsSphericalJoint` and `PhysicsFixedJoint` between two entities' pins (`entity.pins.set(named:position:orientation:)`), each `try joint.addToSimulation()`. RealityKit has no vehicle: a car the person drives is moved by the app, as most are. Collisions arrive as `CollisionEvents.Began` from the scene the world is in, which can change when the view is made again: in `update`, subscribe when `scene.root.scene` isn't the one subscribed to, keep the `EventSubscription`, and use the event for sounds and scores; a `CollisionComponent` with `mode: .trigger` is a zone felt but not hit (a goal, a pickup). Physics costs a frame's time too: resting bodies sleep by themselves, so leave them be; keep to a few hundred dynamic bodies, the simplest shapes that do, and no body made per frame.
18
+
19
+ Model a real thing from a picture of it, never from memory alone. Before writing a main prop that is a real object (a car model, a building, a piece of furniture, an animal), get a reference: the person's photo from the chat, else one `make_art` of the object alone on a plain background, seen straight from the side (or the front, for something whose face matters), whole and uncropped. Read off it what code needs: its outline, proportions (length to height, where the parts begin and end), colors and the parts that make it recognizable. Small or generic props (a box, a pole, a cup) need none.
20
+
21
+ Each prop that matters goes in `props` by name, and look_at_app with `prop` shows it on its own from four sides. Every distinct object made by its own function (a vehicle, a character, furniture, a machine) is a prop, the player's or main object first, and goes into the scene with `scene.place("car", at:heading:)`, which returns the entity to keep and move: so placed, a change to its code shows in the open app; other changes to the scene show when it reopens. Compare that with the reference: shape, proportions, colors, parts. Fix and look again, up to three rounds for the main props; background things get one look.
22
+
23
+ LampSceneView already avoids RealityKit's flicker; keep it that way: no sun shadows (they make the whole picture flicker; `lampShadow` instead), and flat things laid on others (roads, markings, decals, a sign's writing) a few centimeters above them, never at the same height. After big changes, look_at_app with `motion`.
24
+
25
+ A model code can't reasonably make can come ready-made from the `assets` tool (the assets skill), which fetches the .glb into Assets/<pack>/ and credits it: turn it into USD with `usdextract -o Assets/Name Assets/<pack>/name.glb` (part of macOS), and load it with `try await Entity(contentsOf: LampAssets.url("Name/name.usdc")!)`.
26
+
27
+ A real place (a town to drive, a campus, a neighborhood) is built from map data: open the maps skill too.
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: scripting
3
+ description: LampScript, for behavior nobody can write in advance - what happens when two invented things meet, how a new kind of actor acts, a rule the person described in words - with the API it exposes and how scripts are written, cached and run. Read before using it.
4
+ ---
5
+
6
+ # Behavior written while the app runs
7
+
8
+ When the app needs behavior nobody can write in advance (what happens when two invented things meet, how a new kind
9
+ of actor acts, a rule the person just described in words), use `LampScript` from LampSupport.swift:
10
+
11
+ 1. Expose a small, well-described API of what scripts may do (spawn, move, remove, say, plus `isTrue`/`ask` for
12
+ judgment).
13
+ 2. Set `purpose` to a sentence about the app.
14
+ 3. `write(...)` a script for a cache key, then `run(...)` it.
15
+
16
+ Scripts are plain JavaScript in a sealed context with a time limit, cached by key in LampStore. Keep rendering,
17
+ physics and movement in Swift; scripts decide what should happen, not how to draw it.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: share-extension
3
+ description: A share extension (Share/) that puts the app in the person's share sheets and takes in links, text, pictures and files without opening it - ShareView, LampShare in the app, signing, and what to tell the person. Read before writing or changing anything in Share/.
4
+ ---
5
+
6
+ # A share extension
7
+
8
+ Write Share/ShareView.swift: `struct ShareView: View { let items: [LampShare.Item]; var body: some View {
9
+ LampShareSheet(items: items) } }` shows what's shared with Cancel and Save; a view of your own (a note, a list to file
10
+ it in) ends with `LampShare.send(items)` or `LampShare.cancel()`. No `@main` there: Lamp builds the folder as a small
11
+ separate program with Share/LampShareSupport.swift, which Lamp writes (never edit it), and nothing from Sources/.
12
+
13
+ In the app, at launch, `LampShare.onReceive { items in … }` gets each share once, also those made while it was closed:
14
+ `item.kind` (.text, .link, .image, .file), `item.text`, `item.url`, `item.name`, `item.image`, `item.data`; save what
15
+ you keep there, as the files go after.
16
+
17
+ You can't open a share sheet: check that it builds, and tell the user in a sentence that the app is in their share
18
+ sheet.
19
+
20
+ - On a Mac it needs Lamp to sign the app for the user's Apple team (`look_at_app` says when it can't), and macOS keeps
21
+ a new one off until the user turns it on once: Edit Extensions… at the foot of a Share menu.
22
+ - In an app for the Mac and iPhone it is the iPhone half's: the Mac half has none.