lecodes-sdk 0.19.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 (367) hide show
  1. package/README.md +114 -0
  2. package/dist/global.d.ts +503 -0
  3. package/dist/host.d.ts +61 -0
  4. package/dist/inject.js +4730 -0
  5. package/dist/types/animate/animate.d.ts +20 -0
  6. package/dist/types/animate/bezier.d.ts +2 -0
  7. package/dist/types/animate/easings.d.ts +21 -0
  8. package/dist/types/canvas/Canvas.d.ts +168 -0
  9. package/dist/types/core/Aspect.d.ts +171 -0
  10. package/dist/types/core/InspectorUI.d.ts +88 -0
  11. package/dist/types/core/StateMachine.d.ts +81 -0
  12. package/dist/types/core/color.d.ts +13 -0
  13. package/dist/types/core/compWrite.d.ts +11 -0
  14. package/dist/types/core/events.d.ts +11 -0
  15. package/dist/types/core/fields.d.ts +58 -0
  16. package/dist/types/core/registry.d.ts +7 -0
  17. package/dist/types/core/signals.d.ts +29 -0
  18. package/dist/types/core/time.d.ts +31 -0
  19. package/dist/types/g2/Camera2D.d.ts +19 -0
  20. package/dist/types/g2/CharacterController2D.d.ts +134 -0
  21. package/dist/types/g2/Node2D.d.ts +91 -0
  22. package/dist/types/g2/OneWay2D.d.ts +24 -0
  23. package/dist/types/g2/Physics2D.d.ts +147 -0
  24. package/dist/types/g2/Scene2D.d.ts +72 -0
  25. package/dist/types/g2/Shape2D.d.ts +58 -0
  26. package/dist/types/g2/Sprite.d.ts +51 -0
  27. package/dist/types/g2/SpriteAnimation.d.ts +50 -0
  28. package/dist/types/g2/SpriteSheet.d.ts +69 -0
  29. package/dist/types/g2/Texture2D.d.ts +16 -0
  30. package/dist/types/g2/Tilemap.d.ts +20 -0
  31. package/dist/types/g2/Tileset.d.ts +32 -0
  32. package/dist/types/g2/Trigger2D.d.ts +20 -0
  33. package/dist/types/g2/autotile.d.ts +133 -0
  34. package/dist/types/g2/cells.d.ts +14 -0
  35. package/dist/types/g2/defineScene2d.d.ts +141 -0
  36. package/dist/types/g2/groups2d.d.ts +16 -0
  37. package/dist/types/g2/loop.d.ts +4 -0
  38. package/dist/types/g2/scenarios2d.d.ts +30 -0
  39. package/dist/types/g2/touch.d.ts +2 -0
  40. package/dist/types/gl/Camera.d.ts +79 -0
  41. package/dist/types/gl/CameraPlace.d.ts +26 -0
  42. package/dist/types/gl/CharacterController.d.ts +98 -0
  43. package/dist/types/gl/Gearbox.d.ts +86 -0
  44. package/dist/types/gl/Geometry.d.ts +39 -0
  45. package/dist/types/gl/IK.d.ts +53 -0
  46. package/dist/types/gl/InstancedMesh.d.ts +46 -0
  47. package/dist/types/gl/Light.d.ts +73 -0
  48. package/dist/types/gl/Lightmap.d.ts +85 -0
  49. package/dist/types/gl/Locomotion.d.ts +279 -0
  50. package/dist/types/gl/Material.d.ts +100 -0
  51. package/dist/types/gl/Mesh.d.ts +33 -0
  52. package/dist/types/gl/Model.d.ts +53 -0
  53. package/dist/types/gl/NavAgent.d.ts +99 -0
  54. package/dist/types/gl/NavMesh.d.ts +169 -0
  55. package/dist/types/gl/Node.d.ts +99 -0
  56. package/dist/types/gl/Noise.d.ts +20 -0
  57. package/dist/types/gl/Particles.d.ts +277 -0
  58. package/dist/types/gl/Physics.d.ts +91 -0
  59. package/dist/types/gl/Plane.d.ts +19 -0
  60. package/dist/types/gl/Ragdoll.d.ts +86 -0
  61. package/dist/types/gl/Ray.d.ts +8 -0
  62. package/dist/types/gl/Scene.d.ts +221 -0
  63. package/dist/types/gl/Shape.d.ts +122 -0
  64. package/dist/types/gl/Terrain.d.ts +280 -0
  65. package/dist/types/gl/Texture.d.ts +27 -0
  66. package/dist/types/gl/Trigger.d.ts +10 -0
  67. package/dist/types/gl/Vehicle.d.ts +191 -0
  68. package/dist/types/gl/Wheel.d.ts +95 -0
  69. package/dist/types/gl/animation/AnimationClip.d.ts +60 -0
  70. package/dist/types/gl/animation/Animator.d.ts +219 -0
  71. package/dist/types/gl/animation/Layer.d.ts +31 -0
  72. package/dist/types/gl/animation/Loop.d.ts +17 -0
  73. package/dist/types/gl/animation/Playback.d.ts +36 -0
  74. package/dist/types/gl/animation/core.d.ts +367 -0
  75. package/dist/types/gl/controls.d.ts +19 -0
  76. package/dist/types/gl/physicsEvents.d.ts +1 -0
  77. package/dist/types/gl/scenarios.d.ts +98 -0
  78. package/dist/types/gl/state.d.ts +5 -0
  79. package/dist/types/gl/terrainMesh.d.ts +46 -0
  80. package/dist/types/gl/touch.d.ts +2 -0
  81. package/dist/types/inject.d.ts +123 -0
  82. package/dist/types/math/Mathf.d.ts +39 -0
  83. package/dist/types/math/mat4.d.ts +66 -0
  84. package/dist/types/math/quat.d.ts +53 -0
  85. package/dist/types/math/vec.d.ts +129 -0
  86. package/dist/types/net/codec.d.ts +25 -0
  87. package/dist/types/net/core.d.ts +106 -0
  88. package/dist/types/net/index.d.ts +80 -0
  89. package/dist/types/net/replication.d.ts +101 -0
  90. package/dist/types/plugins/camera.d.ts +25 -0
  91. package/dist/types/plugins/geolocation.d.ts +39 -0
  92. package/dist/types/plugins/oauth.d.ts +25 -0
  93. package/dist/types/plugins/permission.d.ts +1 -0
  94. package/dist/types/plugins/push.d.ts +46 -0
  95. package/dist/types/plugins/qr.d.ts +21 -0
  96. package/dist/types/plugins/service.d.ts +33 -0
  97. package/dist/types/runtime/app.d.ts +67 -0
  98. package/dist/types/runtime/appEvents.d.ts +7 -0
  99. package/dist/types/runtime/channel.d.ts +1 -0
  100. package/dist/types/runtime/clipboard.d.ts +7 -0
  101. package/dist/types/runtime/datetime.d.ts +80 -0
  102. package/dist/types/runtime/device.d.ts +126 -0
  103. package/dist/types/runtime/fetch.d.ts +31 -0
  104. package/dist/types/runtime/files.d.ts +33 -0
  105. package/dist/types/runtime/input.d.ts +121 -0
  106. package/dist/types/runtime/media.d.ts +46 -0
  107. package/dist/types/runtime/misc.d.ts +11 -0
  108. package/dist/types/runtime/net.d.ts +15 -0
  109. package/dist/types/runtime/rpc.d.ts +44 -0
  110. package/dist/types/runtime/service.d.ts +1 -0
  111. package/dist/types/runtime/share.d.ts +2 -0
  112. package/dist/types/runtime/storage.d.ts +5 -0
  113. package/dist/types/runtime/touch.d.ts +56 -0
  114. package/dist/types/scene/defineScene.d.ts +296 -0
  115. package/dist/types/scene/editorPlugins.d.ts +82 -0
  116. package/dist/types/scene/gizmos.d.ts +56 -0
  117. package/dist/types/scene/grammar.d.ts +56 -0
  118. package/dist/types/scene/level.d.ts +98 -0
  119. package/dist/types/scene/material.d.ts +76 -0
  120. package/dist/types/server/auth/appConfig.d.ts +16 -0
  121. package/dist/types/server/auth/global.d.ts +56 -0
  122. package/dist/types/server/auth/models.d.ts +164 -0
  123. package/dist/types/server/auth/types.d.ts +56 -0
  124. package/dist/types/server/channel.d.ts +28 -0
  125. package/dist/types/server/context.d.ts +27 -0
  126. package/dist/types/server/db/defineDb.d.ts +36 -0
  127. package/dist/types/server/db/fields.d.ts +146 -0
  128. package/dist/types/server/db/index.d.ts +6 -0
  129. package/dist/types/server/db/marci/query.d.ts +326 -0
  130. package/dist/types/server/db/types.d.ts +163 -0
  131. package/dist/types/server/errors.d.ts +8 -0
  132. package/dist/types/server/inject.d.ts +5 -0
  133. package/dist/types/ui/NativeView.d.ts +38 -0
  134. package/dist/types/ui/UI.d.ts +27 -0
  135. package/dist/types/ui/UIBottomSheet.d.ts +71 -0
  136. package/dist/types/ui/UIButton.d.ts +30 -0
  137. package/dist/types/ui/UIContainer.d.ts +33 -0
  138. package/dist/types/ui/UIImage.d.ts +35 -0
  139. package/dist/types/ui/UIInput.d.ts +110 -0
  140. package/dist/types/ui/UIModal.d.ts +70 -0
  141. package/dist/types/ui/UINode.d.ts +363 -0
  142. package/dist/types/ui/UIPager.d.ts +123 -0
  143. package/dist/types/ui/UIPopover.d.ts +39 -0
  144. package/dist/types/ui/UIScreen.d.ts +57 -0
  145. package/dist/types/ui/UIScrollable.d.ts +40 -0
  146. package/dist/types/ui/UISpacer.d.ts +9 -0
  147. package/dist/types/ui/UITabs.d.ts +96 -0
  148. package/dist/types/ui/UIText.d.ts +19 -0
  149. package/dist/types/ui/UIVideo.d.ts +28 -0
  150. package/dist/types/ui/UIVirtualizedList.d.ts +97 -0
  151. package/dist/types/ui/UIWidget.d.ts +65 -0
  152. package/dist/types/ui/fonts.d.ts +9 -0
  153. package/dist/types/ui/presentable.d.ts +68 -0
  154. package/dist/types/ui/router.d.ts +40 -0
  155. package/dist/types/ui/theme.d.ts +26 -0
  156. package/dist/types.json +1 -0
  157. package/package.json +46 -0
  158. package/prompts/2d.md +395 -0
  159. package/prompts/3d-scene-files.md +113 -0
  160. package/prompts/3d-scene.md +119 -0
  161. package/prompts/3d.md +303 -0
  162. package/prompts/README.md +142 -0
  163. package/prompts/ar.md +109 -0
  164. package/prompts/canvas.md +27 -0
  165. package/prompts/compose.ts +46 -0
  166. package/prompts/concept.md +49 -0
  167. package/prompts/core-design.md +75 -0
  168. package/prompts/core.md +264 -0
  169. package/prompts/design.md +218 -0
  170. package/prompts/dist/2d-game.md +1530 -0
  171. package/prompts/dist/3d-app.md +1672 -0
  172. package/prompts/dist/ar-app.md +1548 -0
  173. package/prompts/dist/concept.md +49 -0
  174. package/prompts/dist/design.md +498 -0
  175. package/prompts/dist/ui-app.md +1134 -0
  176. package/prompts/index.md +37 -0
  177. package/prompts/intake-prompt.md +33 -0
  178. package/prompts/namer-prompt.md +12 -0
  179. package/prompts/router-prompt.md +50 -0
  180. package/prompts/select.ts +111 -0
  181. package/prompts/ui-design.md +203 -0
  182. package/prompts/ui.md +803 -0
  183. package/src/animate/animate.ts +238 -0
  184. package/src/animate/bezier.ts +138 -0
  185. package/src/animate/easings.ts +126 -0
  186. package/src/bridges.d.ts +1345 -0
  187. package/src/canvas/Canvas.ts +305 -0
  188. package/src/compile/__tests__/assetIconMacro.test.ts +219 -0
  189. package/src/compile/__tests__/assetMacro.test.ts +74 -0
  190. package/src/compile/__tests__/assetName.test.ts +55 -0
  191. package/src/compile/__tests__/compile.test.ts +287 -0
  192. package/src/compile/__tests__/detectEntry.test.ts +132 -0
  193. package/src/compile/__tests__/fontMacro.test.ts +199 -0
  194. package/src/compile/aspectMacro.ts +86 -0
  195. package/src/compile/assetIconMacro.ts +384 -0
  196. package/src/compile/assetMacro.ts +146 -0
  197. package/src/compile/assetName.ts +50 -0
  198. package/src/compile/bundler.ts +287 -0
  199. package/src/compile/compileProject.ts +127 -0
  200. package/src/compile/detectEntry.ts +128 -0
  201. package/src/compile/fontMacro.ts +459 -0
  202. package/src/compile/fontRegistry.ts +78 -0
  203. package/src/compile/header.ts +67 -0
  204. package/src/compile/index.ts +100 -0
  205. package/src/compile/libraryImports.ts +52 -0
  206. package/src/compile/liteMaterial.ts +247 -0
  207. package/src/compile/sceneEditor.ts +88 -0
  208. package/src/compile/serverSplit.ts +233 -0
  209. package/src/compile/serverTypes.ts +227 -0
  210. package/src/compile/sfnt.ts +98 -0
  211. package/src/compile/shaderSchema.ts +202 -0
  212. package/src/compile/shaderTargets.ts +77 -0
  213. package/src/compile/sourcemap.ts +25 -0
  214. package/src/core/Aspect.ts +568 -0
  215. package/src/core/InspectorUI.ts +212 -0
  216. package/src/core/StateMachine.ts +308 -0
  217. package/src/core/__tests__/stateMachine.test.ts +132 -0
  218. package/src/core/color.ts +66 -0
  219. package/src/core/compWrite.ts +42 -0
  220. package/src/core/events.ts +38 -0
  221. package/src/core/fields.ts +120 -0
  222. package/src/core/registry.ts +23 -0
  223. package/src/core/signals.ts +277 -0
  224. package/src/core/time.ts +84 -0
  225. package/src/g2/Camera2D.ts +40 -0
  226. package/src/g2/CharacterController2D.ts +276 -0
  227. package/src/g2/Node2D.ts +267 -0
  228. package/src/g2/OneWay2D.ts +66 -0
  229. package/src/g2/Physics2D.ts +346 -0
  230. package/src/g2/Scene2D.ts +209 -0
  231. package/src/g2/Shape2D.ts +259 -0
  232. package/src/g2/Sprite.ts +89 -0
  233. package/src/g2/SpriteAnimation.ts +171 -0
  234. package/src/g2/SpriteSheet.ts +166 -0
  235. package/src/g2/Texture2D.ts +47 -0
  236. package/src/g2/Tilemap.ts +41 -0
  237. package/src/g2/Tileset.ts +71 -0
  238. package/src/g2/Trigger2D.ts +77 -0
  239. package/src/g2/autotile.ts +433 -0
  240. package/src/g2/cells.ts +91 -0
  241. package/src/g2/defineScene2d.ts +381 -0
  242. package/src/g2/groups2d.ts +106 -0
  243. package/src/g2/loop.ts +50 -0
  244. package/src/g2/scenarios2d.ts +69 -0
  245. package/src/g2/touch.ts +83 -0
  246. package/src/gl/Camera.ts +160 -0
  247. package/src/gl/CameraPlace.ts +52 -0
  248. package/src/gl/CharacterController.ts +238 -0
  249. package/src/gl/Gearbox.ts +212 -0
  250. package/src/gl/Geometry.ts +279 -0
  251. package/src/gl/IK.ts +193 -0
  252. package/src/gl/InstancedMesh.ts +132 -0
  253. package/src/gl/Light.ts +135 -0
  254. package/src/gl/Lightmap.ts +402 -0
  255. package/src/gl/Locomotion.ts +498 -0
  256. package/src/gl/Material.ts +279 -0
  257. package/src/gl/Mesh.ts +83 -0
  258. package/src/gl/Model.ts +124 -0
  259. package/src/gl/NavAgent.ts +337 -0
  260. package/src/gl/NavMesh.ts +397 -0
  261. package/src/gl/Node.ts +350 -0
  262. package/src/gl/Noise.ts +30 -0
  263. package/src/gl/Particles.ts +676 -0
  264. package/src/gl/Physics.ts +222 -0
  265. package/src/gl/Plane.ts +53 -0
  266. package/src/gl/Ragdoll.ts +270 -0
  267. package/src/gl/Ray.ts +16 -0
  268. package/src/gl/Scene.ts +505 -0
  269. package/src/gl/Shape.ts +409 -0
  270. package/src/gl/Terrain.ts +1092 -0
  271. package/src/gl/Texture.ts +63 -0
  272. package/src/gl/Trigger.ts +45 -0
  273. package/src/gl/Vehicle.ts +473 -0
  274. package/src/gl/Wheel.ts +240 -0
  275. package/src/gl/animation/AnimationClip.ts +204 -0
  276. package/src/gl/animation/Animator.ts +329 -0
  277. package/src/gl/animation/Layer.ts +39 -0
  278. package/src/gl/animation/Loop.ts +31 -0
  279. package/src/gl/animation/Playback.ts +52 -0
  280. package/src/gl/animation/core.ts +670 -0
  281. package/src/gl/controls.ts +95 -0
  282. package/src/gl/physicsEvents.ts +20 -0
  283. package/src/gl/scenarios.ts +291 -0
  284. package/src/gl/state.ts +6 -0
  285. package/src/gl/terrainMesh.ts +219 -0
  286. package/src/gl/touch.ts +68 -0
  287. package/src/host.d.ts +61 -0
  288. package/src/inject.ts +203 -0
  289. package/src/math/Mathf.ts +118 -0
  290. package/src/math/mat4.ts +278 -0
  291. package/src/math/quat.ts +232 -0
  292. package/src/math/vec.ts +255 -0
  293. package/src/net/codec.ts +119 -0
  294. package/src/net/core.ts +384 -0
  295. package/src/net/index.ts +181 -0
  296. package/src/net/replication.ts +622 -0
  297. package/src/plugins/camera.ts +81 -0
  298. package/src/plugins/geolocation.ts +123 -0
  299. package/src/plugins/oauth.ts +61 -0
  300. package/src/plugins/permission.ts +7 -0
  301. package/src/plugins/push.ts +132 -0
  302. package/src/plugins/qr.ts +73 -0
  303. package/src/plugins/service.ts +47 -0
  304. package/src/runtime/app.ts +101 -0
  305. package/src/runtime/appEvents.ts +54 -0
  306. package/src/runtime/channel.ts +61 -0
  307. package/src/runtime/clipboard.ts +20 -0
  308. package/src/runtime/datetime.ts +329 -0
  309. package/src/runtime/device.ts +293 -0
  310. package/src/runtime/fetch.ts +77 -0
  311. package/src/runtime/files.ts +108 -0
  312. package/src/runtime/input.ts +175 -0
  313. package/src/runtime/media.ts +111 -0
  314. package/src/runtime/misc.ts +16 -0
  315. package/src/runtime/net.ts +36 -0
  316. package/src/runtime/rpc.ts +218 -0
  317. package/src/runtime/service.ts +83 -0
  318. package/src/runtime/share.ts +9 -0
  319. package/src/runtime/storage.ts +13 -0
  320. package/src/runtime/touch.ts +76 -0
  321. package/src/scene/defineScene.ts +1396 -0
  322. package/src/scene/editorPlugins.ts +110 -0
  323. package/src/scene/gizmos.ts +148 -0
  324. package/src/scene/grammar.ts +120 -0
  325. package/src/scene/level.ts +296 -0
  326. package/src/scene/material.ts +188 -0
  327. package/src/server/auth/appConfig.ts +12 -0
  328. package/src/server/auth/global.ts +80 -0
  329. package/src/server/auth/host.ts +318 -0
  330. package/src/server/auth/models.ts +83 -0
  331. package/src/server/auth/types.ts +50 -0
  332. package/src/server/channel.ts +56 -0
  333. package/src/server/context.ts +36 -0
  334. package/src/server/db/defineDb.ts +237 -0
  335. package/src/server/db/fields.ts +132 -0
  336. package/src/server/db/httpTransport.ts +93 -0
  337. package/src/server/db/index.ts +7 -0
  338. package/src/server/db/marci/query.ts +412 -0
  339. package/src/server/db/types.ts +202 -0
  340. package/src/server/errors.ts +12 -0
  341. package/src/server/host.ts +74 -0
  342. package/src/server/inject.ts +13 -0
  343. package/src/server/runtime.ts +133 -0
  344. package/src/server/validate.ts +87 -0
  345. package/src/ui/NativeView.ts +142 -0
  346. package/src/ui/UI.ts +39 -0
  347. package/src/ui/UIBottomSheet.ts +139 -0
  348. package/src/ui/UIButton.ts +101 -0
  349. package/src/ui/UIContainer.ts +60 -0
  350. package/src/ui/UIImage.ts +83 -0
  351. package/src/ui/UIInput.ts +185 -0
  352. package/src/ui/UIModal.ts +139 -0
  353. package/src/ui/UINode.ts +830 -0
  354. package/src/ui/UIPager.ts +362 -0
  355. package/src/ui/UIPopover.ts +100 -0
  356. package/src/ui/UIScreen.ts +123 -0
  357. package/src/ui/UIScrollable.ts +87 -0
  358. package/src/ui/UISpacer.ts +14 -0
  359. package/src/ui/UITabs.ts +236 -0
  360. package/src/ui/UIText.ts +51 -0
  361. package/src/ui/UIVideo.ts +88 -0
  362. package/src/ui/UIVirtualizedList.ts +241 -0
  363. package/src/ui/UIWidget.ts +127 -0
  364. package/src/ui/fonts.ts +13 -0
  365. package/src/ui/presentable.ts +117 -0
  366. package/src/ui/router.ts +132 -0
  367. package/src/ui/theme.ts +84 -0
@@ -0,0 +1,111 @@
1
+ // Audio / video playback over the host. Ported from worker/src/MediaPlayer.ts, with the listener
2
+ // boilerplate folded into the shared Emitter. VideoPlayer.texture (a 3D Texture) is wired in Phase 4
3
+ // when the Texture type exists — see gl/.
4
+ //
5
+ // The host no longer routes end-of-playback events back by id through a Registry: each player hands
6
+ // the host a `_finished` callback at creation time. The host holds the JS closure directly — valid
7
+ // on every backend (web JS, Android quickjs, iOS JavaScriptCore) — and invokes it when a play-through
8
+ // completes, so there is no id table to keep in sync.
9
+
10
+ import { Emitter } from "../core/events"
11
+ import { Texture } from "../gl/Texture"
12
+
13
+ type MediaEvents = {
14
+ /** Fired at each loop boundary while `loop` is true. */
15
+ loopReached: () => void
16
+ /** Fired once when playback reaches the end while `loop` is false. */
17
+ completed: () => void
18
+ }
19
+
20
+ abstract class MediaPlayer extends Emitter<MediaEvents> {
21
+ protected _id = -1
22
+ protected _src = ""
23
+ private _playing = false
24
+ private _loop = false
25
+ private _volume = 1
26
+ private _disposed = false
27
+
28
+ // Every host-touching operation runs through this so a disposed player can never address a freed
29
+ // (and possibly reused) host slot.
30
+ private _assertAlive(): void {
31
+ if (this._disposed) throw new Error("MediaPlayer has been disposed")
32
+ }
33
+
34
+ play(): void { this.playing = true }
35
+ pause(): void { this.playing = false }
36
+
37
+ get playing(): boolean { return this._playing }
38
+ set playing(value: boolean) {
39
+ this._assertAlive()
40
+ this._playing = value
41
+ _creatorUtils.updateMediaPlayerPlaying(this._id, value)
42
+ }
43
+
44
+ get volume(): number { return this._volume }
45
+ set volume(value: number) {
46
+ this._assertAlive()
47
+ this._volume = value
48
+ _creatorUtils.updateMediaPlayerVolume(this._id, value)
49
+ }
50
+
51
+ get loop(): boolean { return this._loop }
52
+ set loop(value: boolean) {
53
+ this._assertAlive()
54
+ this._loop = value
55
+ _creatorUtils.updateMediaPlayerLoop(this._id, value)
56
+ }
57
+
58
+ /** Current playback position, in seconds. Settable to seek. */
59
+ get time(): number { this._assertAlive(); return _creatorUtils.getMediaPlayerTime(this._id) }
60
+ set time(value: number) { this._assertAlive(); _creatorUtils.setMediaPlayerTime(this._id, value) }
61
+
62
+ /** Total media length in seconds (0 until metadata has loaded). */
63
+ get duration(): number { this._assertAlive(); return _creatorUtils.getMediaPlayerDuration(this._id) }
64
+
65
+ /** True once {@link dispose} has been called; the player is unusable afterwards. */
66
+ get disposed(): boolean { return this._disposed }
67
+
68
+ /**
69
+ * Release the underlying host media resource (decoder, network, buffers) immediately and detach
70
+ * all listeners. Idempotent. Any further use of the player throws.
71
+ */
72
+ dispose(): void {
73
+ if (this._disposed) return
74
+ this._disposed = true
75
+ this._playing = false
76
+ this.clearListeners()
77
+ _creatorUtils.removeMediaPlayer(this._id)
78
+ }
79
+
80
+ /** @internal — the host calls this when a play-through finishes. */
81
+ protected _finished(): void {
82
+ if (this._disposed) return
83
+ if (this._loop) {
84
+ this.dispatch("loopReached")
85
+ } else {
86
+ this._playing = false
87
+ this.dispatch("completed")
88
+ }
89
+ }
90
+ }
91
+
92
+ export class AudioPlayer extends MediaPlayer {
93
+ constructor(src?: string) {
94
+ super()
95
+ this._src = src ?? ""
96
+ this._id = _creatorUtils.createAudioPlayer(this._src, () => this._finished())
97
+ }
98
+ }
99
+
100
+ export class VideoPlayer extends MediaPlayer {
101
+ constructor(src?: string) {
102
+ super()
103
+ this._src = src ?? ""
104
+ this._id = _creatorUtils.createVideoPlayer(this._src, () => this._finished())
105
+ }
106
+
107
+ /** A 3D Texture that samples this video (e.g. for a Material.video()). */
108
+ get texture(): Texture {
109
+ return new Texture(0, 0, _creator.createMediaPlayerTexture(this._id))
110
+ }
111
+ }
@@ -0,0 +1,16 @@
1
+ // Small platform globals that are real (not engine-specific). Grown in Phase 1.
2
+
3
+ /** Show a transient toast notification. */
4
+ export const toast = (msg: string): void => _creatorUI.toast(msg)
5
+
6
+ /** Open `url` in the system browser / external handler (fire-and-forget, like `share`). Silent
7
+ * no-op on hosts without one (headless). */
8
+ export const openURL = (url: string): void => _creatorUtils.openUrl?.(url)
9
+
10
+ export type SvgSourceValue = {
11
+ readonly svg: string
12
+ tintColor: string | null
13
+ }
14
+
15
+ /** Wrap raw SVG XML so it can be used as an image source. */
16
+ export const SvgSource = (svg: string): SvgSourceValue => ({ svg, tintColor: null })
@@ -0,0 +1,36 @@
1
+ // WebSocket over the host bridge. Same event surface as the browser's (open/message/close/error)
2
+ // via the shared Emitter. Ported from worker/src/WebSocket.ts.
3
+
4
+ import { Emitter } from "../core/events"
5
+
6
+ type SocketEvents = {
7
+ open: () => void
8
+ message: (data: any) => void
9
+ close: (code?: number) => void
10
+ error: () => void
11
+ }
12
+
13
+ export class WebSocket extends Emitter<SocketEvents> {
14
+ private _id: number | null = null
15
+
16
+ constructor(url: string, headers?: Record<string, string>) {
17
+ super()
18
+ this._id = _creatorUtils.websocketOpen(url, (channel, data) => this._onMessage(channel, data), headers)
19
+ }
20
+
21
+ send(message: string | ArrayBuffer): void {
22
+ if (this._id !== null) _creatorUtils.websocketSend(this._id, message)
23
+ }
24
+
25
+ close(): void {
26
+ if (this._id !== null) {
27
+ _creatorUtils.websocketClose(this._id)
28
+ this._id = null
29
+ }
30
+ }
31
+
32
+ private _onMessage(channel: string, data: any): void {
33
+ if (data !== undefined && data !== null) this.dispatch(channel as keyof SocketEvents, data)
34
+ else this.dispatch(channel as keyof SocketEvents)
35
+ }
36
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Client transport for the app backend (docs/backend-plan.md §3.2 / §3.3). The compiler replaces
3
+ * every `*.server.ts` module in the client bundle with a stub whose exports are built by the three
4
+ * globals below — user code never calls them; it imports the server function and calls it.
5
+ *
6
+ * export const listNotes = __rpc("<serverUrl>", "notes.server.ts#listNotes")
7
+ * export const chat = __channel("<serverUrl>", "chat.server.ts#chat")
8
+ * export const db = __serverOnly("schema.server.ts#db")
9
+ *
10
+ * Wire (implemented by the runner):
11
+ * POST <serverUrl>/api/<id> body {"args":[…]}, `authorization: Bearer <session>` when known
12
+ * → 200 {"ok":true,"result":…,"session"?:"…"} | {"ok":false,"status":n,"message":"…","session"?:"…"}
13
+ * WS <serverUrl>/ws frames: → {t:"hello",session} {t:"sub",id,ch,topic} {t:"unsub",id}
14
+ * ← {t:"session",session} {t:"ok",id} {t:"err",id,status,message} {t:"ev",ch,topic,event,data}
15
+ * (`ev` is addressed by channel + topic, not by subscription id, so the server can fan one publish out
16
+ * to every socket of a topic natively; the client delivers it to each matching subscription.)
17
+ *
18
+ * The session token is transport-owned (cookie-like): stored under `lecodes.session:<serverUrl>` in
19
+ * localStorage, sent on every call and on the socket, replaced whenever a response carries `session`.
20
+ * User code never sees it — "am I logged in" is an endpoint (`me()`), see the plan.
21
+ */
22
+
23
+ import { fetch } from "./fetch"
24
+ import { localStorage } from "./storage"
25
+ import { WebSocket } from "./net"
26
+
27
+ /** Rejection value of a failed endpoint call: `status` mirrors the server's `ApiError`
28
+ * (0 = the request itself failed: no network / no server). */
29
+ export class RpcError extends Error {
30
+ readonly status: number
31
+ constructor(status: number, message: string) {
32
+ super(message)
33
+ this.name = "RpcError"
34
+ this.status = status
35
+ }
36
+ }
37
+
38
+ // ───────────────────────────── session token ─────────────────────────────
39
+
40
+ const sessionKey = (serverUrl: string) => `lecodes.session:${serverUrl}`
41
+ const getSession = (serverUrl: string): string | null => {
42
+ try { return localStorage.getItem(sessionKey(serverUrl)) } catch { return null }
43
+ }
44
+ const setSession = (serverUrl: string, token: string | null) => {
45
+ try {
46
+ if (token) localStorage.setItem(sessionKey(serverUrl), token)
47
+ else localStorage.removeItem(sessionKey(serverUrl))
48
+ } catch { /* storage-less host: the session lives for this run only */ }
49
+ sockets.get(serverUrl)?.onSessionChanged(token)
50
+ }
51
+
52
+ // ───────────────────────────── endpoints ─────────────────────────────
53
+
54
+ const noServer = (id: string) => new RpcError(0, `Endpoint ${id}: the project has no deployed server (compile with serverUrl)`)
55
+
56
+ /** Build the client proxy of endpoint `id`. Positional args travel as a JSON array. */
57
+ export const __rpc = (serverUrl: string, id: string) => {
58
+ const call = async (...args: unknown[]): Promise<any> => {
59
+ if (!serverUrl) throw noServer(id)
60
+ const headers: Record<string, string> = { "content-type": "application/json" }
61
+ const session = getSession(serverUrl)
62
+ if (session) headers.authorization = `Bearer ${session}`
63
+ let res
64
+ try {
65
+ res = await fetch(`${serverUrl}/api/${encodeURIComponent(id)}`, { method: "POST", headers, body: JSON.stringify({ args }) })
66
+ } catch (e) {
67
+ throw new RpcError(0, `Endpoint ${id}: request failed (${(e as Error)?.message ?? e})`)
68
+ }
69
+ let body: any
70
+ try { body = res.json() } catch { body = null }
71
+ res.dispose()
72
+ if (body && typeof body === "object" && "session" in body) setSession(serverUrl, body.session ?? null)
73
+ if (body && body.ok === true) return body.result
74
+ if (body && body.ok === false) throw new RpcError(body.status ?? res.status, body.message ?? "")
75
+ throw new RpcError(res.status, `Endpoint ${id}: unexpected response (HTTP ${res.status})`)
76
+ }
77
+ return call
78
+ }
79
+
80
+ /** A server-only export (db, models, helpers) referenced from client code: any use throws. */
81
+ export const __serverOnly = (id: string): any =>
82
+ new Proxy(function () {} as any, {
83
+ get: (_t, prop) => { if (prop === "then") return undefined; throw new RpcError(0, `${id} is server-only — it can't be used in client code`) },
84
+ apply: () => { throw new RpcError(0, `${id} is server-only — it can't be used in client code`) },
85
+ })
86
+
87
+ // ───────────────────────────── channels ─────────────────────────────
88
+
89
+ type Handlers = Record<string, ((payload: any) => void) | undefined> & {
90
+ /** The socket dropped and came back: subscriptions were re-sent, but events in between are lost — refetch. */
91
+ reconnect?: () => void
92
+ /** The subscription was refused (`onJoin` threw) or the socket can't connect. */
93
+ error?: (e: RpcError) => void
94
+ }
95
+ type Sub = { id: number, ch: string, topic: string, handlers: Handlers, ready: boolean }
96
+
97
+ const BACKOFF_MS = [1000, 2000, 5000, 10000, 30000]
98
+
99
+ /** One multiplexed socket per server URL, shared by every channel of the app. */
100
+ class ChannelSocket {
101
+ private ws: WebSocket | null = null
102
+ private open = false
103
+ private subs = new Map<number, Sub>()
104
+ private nextId = 1
105
+ private attempts = 0
106
+ private timer: ReturnType<typeof setTimeout> | null = null
107
+ private closedByUs = false
108
+ private everOpened = false
109
+ private serverUrl: string
110
+
111
+ constructor(serverUrl: string) { this.serverUrl = serverUrl }
112
+
113
+ subscribe(ch: string, topic: string, handlers: Handlers): { close(): void } {
114
+ const sub: Sub = { id: this.nextId++, ch, topic, handlers, ready: false }
115
+ this.subs.set(sub.id, sub)
116
+ if (this.open) this.send({ t: "sub", id: sub.id, ch, topic })
117
+ else this.connect()
118
+ return {
119
+ close: () => {
120
+ if (!this.subs.delete(sub.id)) return
121
+ if (this.open) this.send({ t: "unsub", id: sub.id })
122
+ if (this.subs.size === 0) this.shutdown()
123
+ },
124
+ }
125
+ }
126
+
127
+ onSessionChanged(token: string | null) {
128
+ if (this.open) this.send({ t: "hello", session: token })
129
+ }
130
+
131
+ private connect() {
132
+ if (this.ws || this.timer !== null) return
133
+ this.closedByUs = false
134
+ const url = this.serverUrl.replace(/^http/, "ws") + "/ws"
135
+ const session = getSession(this.serverUrl)
136
+ const ws = new WebSocket(url, session ? { authorization: `Bearer ${session}` } : undefined)
137
+ this.ws = ws
138
+ ws.addEventListener("open", () => {
139
+ this.open = true
140
+ this.attempts = 0
141
+ this.send({ t: "hello", session: getSession(this.serverUrl) })
142
+ const reconnected = this.everOpened
143
+ this.everOpened = true
144
+ for (const sub of this.subs.values()) {
145
+ sub.ready = false
146
+ this.send({ t: "sub", id: sub.id, ch: sub.ch, topic: sub.topic })
147
+ if (reconnected) sub.handlers.reconnect?.()
148
+ }
149
+ })
150
+ ws.addEventListener("message", (data) => {
151
+ if (typeof data !== "string") return
152
+ let msg: any
153
+ try { msg = JSON.parse(data) } catch { return }
154
+ this.onFrame(msg)
155
+ })
156
+ const onDown = () => {
157
+ if (this.ws !== ws) return
158
+ this.ws = null
159
+ this.open = false
160
+ if (this.closedByUs || this.subs.size === 0) return
161
+ const delay = BACKOFF_MS[Math.min(this.attempts++, BACKOFF_MS.length - 1)]
162
+ this.timer = setTimeout(() => { this.timer = null; this.connect() }, delay)
163
+ }
164
+ ws.addEventListener("close", onDown)
165
+ ws.addEventListener("error", onDown)
166
+ }
167
+
168
+ private onFrame(msg: any) {
169
+ switch (msg?.t) {
170
+ case "session": setSession(this.serverUrl, msg.session ?? null); break
171
+ case "ok": { const s = this.subs.get(msg.id); if (s) s.ready = true; break }
172
+ case "err": {
173
+ const s = this.subs.get(msg.id)
174
+ if (!s) break
175
+ this.subs.delete(msg.id)
176
+ s.handlers.error?.(new RpcError(msg.status ?? 0, msg.message ?? "subscription refused"))
177
+ break
178
+ }
179
+ case "ev": {
180
+ for (const s of this.subs.values()) {
181
+ if (s.ch === msg.ch && s.topic === msg.topic) s.handlers[msg.event]?.(msg.data)
182
+ }
183
+ break
184
+ }
185
+ }
186
+ }
187
+
188
+ private send(frame: unknown) { this.ws?.send(JSON.stringify(frame)) }
189
+
190
+ private shutdown() {
191
+ this.closedByUs = true
192
+ if (this.timer !== null) { clearTimeout(this.timer); this.timer = null }
193
+ this.ws?.close()
194
+ this.ws = null
195
+ this.open = false
196
+ sockets.delete(this.serverUrl)
197
+ }
198
+ }
199
+
200
+ const sockets = new Map<string, ChannelSocket>()
201
+ const socketFor = (serverUrl: string) => {
202
+ let s = sockets.get(serverUrl)
203
+ if (!s) { s = new ChannelSocket(serverUrl); sockets.set(serverUrl, s) }
204
+ return s
205
+ }
206
+
207
+ export interface ClientChannel<E extends Record<string, unknown> = Record<string, unknown>> {
208
+ /** Subscribe to `topic`; handlers are keyed by event name (+ `reconnect`/`error`). Returns `{ close }`. */
209
+ subscribe(topic: string, handlers: { [K in keyof E]?: (payload: E[K]) => void } & { reconnect?: () => void, error?: (e: RpcError) => void }): { close(): void }
210
+ }
211
+
212
+ /** Build the client proxy of channel `id`. */
213
+ export const __channel = (serverUrl: string, id: string): ClientChannel<any> => ({
214
+ subscribe(topic, handlers) {
215
+ if (!serverUrl) throw noServer(id)
216
+ return socketFor(serverUrl).subscribe(id, topic, handlers as Handlers)
217
+ },
218
+ })
@@ -0,0 +1,83 @@
1
+ // A host-registered headless service (geolocation, bluetooth, contacts, …) — the UI-less sibling
2
+ // of NativeView (docs/service-channel-plan.md). The host registers a *capability*
3
+ // (`registerService("geolocation") { params, channel -> ... }`); the SDK talks to it over the
4
+ // shared JSON call/event protocol (runtime/channel.ts) via `_creatorUtils.service*`.
5
+ //
6
+ // Not a public global itself: apps meet services through typed plugin wrappers (Geolocation —
7
+ // src/plugins/) or the raw `Service(name)` global (src/plugins/service.ts), both thin layers
8
+ // over this exactly like QRScanner wraps NativeViewElement.
9
+
10
+ import { _channelCall, _channelEmit, _channelOff, _channelOn, type ChannelListeners } from "./channel"
11
+
12
+ /** @internal Base for typed service plugins. The host session opens lazily on the first `call()`
13
+ * (`on()` only records listeners), and `close()` releases it — a later `call()` reopens a fresh
14
+ * session. Session ids are host-allocated (websocket model): the `onEvent` callback is handed
15
+ * over at open, so no SDK-side ref registry is needed. */
16
+ export class ServiceClient {
17
+ readonly serviceName: string
18
+ readonly params: any
19
+ private _serviceId: number | null = null
20
+ private readonly _listeners: ChannelListeners = {}
21
+
22
+ constructor(serviceName: string, params: any = {}) {
23
+ this.serviceName = serviceName
24
+ this.params = params
25
+ }
26
+
27
+ /** Whether this host registered a `registerService` factory under `name`. */
28
+ static isSupported(name: string): boolean {
29
+ return typeof _creatorUtils !== "undefined" && typeof _creatorUtils.isServiceSupported === "function"
30
+ && _creatorUtils.isServiceSupported(name)
31
+ }
32
+
33
+ /** @internal open (or reuse) the host session; throws when the host has no channel/factory. */
34
+ private _ensureOpen(): number {
35
+ if (this._serviceId !== null) return this._serviceId
36
+ if (typeof _creatorUtils === "undefined" || typeof _creatorUtils.serviceOpen !== "function") {
37
+ throw new Error(`Service("${this.serviceName}") is not supported on this host (requires _creatorUtils.serviceOpen)`)
38
+ }
39
+ const id = _creatorUtils.serviceOpen(this.serviceName, JSON.stringify(this.params ?? {}),
40
+ (event: string, dataJson?: string) => _channelEmit(this._listeners, event, dataJson))
41
+ if (id < 0) {
42
+ throw new Error(`Service("${this.serviceName}") is not registered on this host`)
43
+ }
44
+ this._serviceId = id
45
+ return id
46
+ }
47
+
48
+ /** Invoke a method on the service (`geo.call("getCurrent", options)`). Args and the result are
49
+ * JSON-serialized. Rejects if the host has no such service/method. */
50
+ call(method: string, ...args: any[]): Promise<any> {
51
+ let id: number
52
+ try {
53
+ id = this._ensureOpen()
54
+ } catch (e) {
55
+ return Promise.reject(e)
56
+ }
57
+ return _channelCall(
58
+ typeof _creatorUtils !== "undefined" ? _creatorUtils : undefined, "serviceCall",
59
+ `Service("${this.serviceName}") is not supported on this host (requires _creatorUtils.serviceCall)`,
60
+ id, method, args)
61
+ }
62
+
63
+ /** Subscribe to an event the service emits (`geo.on("position", cb)`). */
64
+ on(event: string, callback: (data?: any) => void): this {
65
+ _channelOn(this._listeners, event, callback)
66
+ return this
67
+ }
68
+ off(event: string, callback: (data?: any) => void): this {
69
+ _channelOff(this._listeners, event, callback)
70
+ return this
71
+ }
72
+
73
+ /** Close the host session (stops whatever the service was doing). Listeners stay registered —
74
+ * a later `call()` opens a fresh session that delivers to them again. */
75
+ close(): void {
76
+ if (this._serviceId === null) return
77
+ const id = this._serviceId
78
+ this._serviceId = null
79
+ if (typeof _creatorUtils !== "undefined" && typeof _creatorUtils.serviceClose === "function") {
80
+ _creatorUtils.serviceClose(id)
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,9 @@
1
+ // Share a media File (image/video) via the OS share sheet. Wraps `_creatorUtils.shareMedia`, which
2
+ // takes the host buffer id behind the File. On iOS the sheet also lets the user save to Files/Photos;
3
+ // on web it saves (downloads) the file. `text` is an optional caption/message.
4
+
5
+ import type { File, FetchResponse } from "./fetch"
6
+
7
+ export function share(media: File | FetchResponse, text?: string): void {
8
+ _creatorUtils.shareMedia((media as any)._id, text)
9
+ }
@@ -0,0 +1,13 @@
1
+ // Key/value persistence backed by the host. Same shape as the web localStorage subset projects use.
2
+
3
+ export const localStorage = {
4
+ getItem(key: string): string | null {
5
+ return _creatorUtils.localStorageGetValue(key)
6
+ },
7
+ setItem(key: string, value: string): void {
8
+ _creatorUtils.localStorageSetValue(key, value)
9
+ },
10
+ removeItem(key: string): void {
11
+ _creatorUtils.localStorageRemoveValue(key)
12
+ },
13
+ }
@@ -0,0 +1,76 @@
1
+ // Pointer event objects delivered to 3D scene/node touch handlers. Ported from worker/src/TouchEvent.ts.
2
+ // The dispatch wiring (reading the active scene, hit entity) is set up in Phase 4 with the 3D Scene;
3
+ // these classes are the injected globals user code receives. `target` is the hit Node (typed loosely
4
+ // here to avoid a forward dependency on gl/).
5
+
6
+ export class ClickEvent<T = any> {
7
+ readonly type = "click"
8
+ readonly pointerId: number
9
+ readonly clientX: number
10
+ readonly clientY: number
11
+ /** World-space hit position (2D scenes only; undefined in 3D). */
12
+ worldX?: number
13
+ worldY?: number
14
+ target!: T
15
+ constructor(clientX: number, clientY: number, pointerId: number) {
16
+ this.clientX = clientX
17
+ this.clientY = clientY
18
+ this.pointerId = pointerId
19
+ }
20
+ }
21
+
22
+ export interface TrackHandler {
23
+ onMove?(pos: { clientX: number, clientY: number, deltaX: number, deltaY: number }): void
24
+ onEnd?(pos: { clientX: number, clientY: number, deltaX: number, deltaY: number }): void
25
+ onCancel?(): void
26
+ claim?: boolean | "pan-x" | "pan-y" | "pan-down" | "pan-up" | "pan-left" | "pan-right"
27
+ }
28
+
29
+ export class TouchStartEvent<T = any> {
30
+ readonly type = "touchstart"
31
+ readonly pointerId: number
32
+ readonly clientX: number
33
+ readonly clientY: number
34
+ /** World-space hit position (2D scenes only; undefined in 3D). */
35
+ worldX?: number
36
+ worldY?: number
37
+ target!: T
38
+ /** @internal — read by the dispatch system after the handler runs. */
39
+ _trackHandler?: TrackHandler
40
+ constructor(clientX: number, clientY: number, pointerId: number) {
41
+ this.clientX = clientX
42
+ this.clientY = clientY
43
+ this.pointerId = pointerId
44
+ }
45
+
46
+ /** Capture subsequent moves/end for this pointer (drag/pan gestures). */
47
+ track(handler: TrackHandler): void {
48
+ this._trackHandler = handler
49
+ }
50
+ }
51
+
52
+ /** Delivered to a `UIButton` `onLongPress` handler when a finger is held on the button past the
53
+ * host's long-press threshold. Like `TouchStartEvent` it can `track(...)` the rest of the gesture —
54
+ * so the common "press-and-hold, then drag to move" flow is one handler: start the drag from here. */
55
+ export class LongPressEvent<T = any> {
56
+ readonly type = "longpress"
57
+ readonly pointerId: number
58
+ readonly clientX: number
59
+ readonly clientY: number
60
+ /** World-space hit position (2D scenes only; undefined in 3D). */
61
+ worldX?: number
62
+ worldY?: number
63
+ target!: T
64
+ /** @internal — read by the dispatch system after the handler runs. */
65
+ _trackHandler?: TrackHandler
66
+ constructor(clientX: number, clientY: number, pointerId: number) {
67
+ this.clientX = clientX
68
+ this.clientY = clientY
69
+ this.pointerId = pointerId
70
+ }
71
+
72
+ /** Capture subsequent moves/end for this pointer — drag the element after the hold. */
73
+ track(handler: TrackHandler): void {
74
+ this._trackHandler = handler
75
+ }
76
+ }