lecodes-sdk 2.2.9 → 2.2.10

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 (61) hide show
  1. package/dist/global.d.ts +42 -1
  2. package/dist/types/gl/Camera.d.ts +5 -2
  3. package/dist/types/gl/Node.d.ts +0 -7
  4. package/dist/types/gl/Scene.d.ts +6 -24
  5. package/dist/types/inject.d.ts +5 -1
  6. package/dist/types/plugin.d.ts +27 -0
  7. package/dist/types/plugins/gen/ar/sdk/ar.d.ts +228 -0
  8. package/dist/types/plugins/gen/ar/sdk/ar.gen.d.ts +73 -0
  9. package/dist/types/plugins/gen/ar/sdk/controls.d.ts +28 -0
  10. package/dist/types/plugins/gen/audio-recorder/sdk/audio-recorder.d.ts +43 -0
  11. package/dist/types/plugins/gen/audio-recorder/sdk/audio-recorder.gen.d.ts +47 -0
  12. package/dist/types/plugins/gen/geolocation/sdk/geolocation.gen.d.ts +6 -2
  13. package/dist/types/plugins/gen/speech/sdk/speech.d.ts +44 -0
  14. package/dist/types/plugins/gen/speech/sdk/speech.gen.d.ts +39 -0
  15. package/dist/types/runtime/permissions.d.ts +16 -0
  16. package/dist/types/version.d.ts +1 -1
  17. package/dist/types.json +1 -1
  18. package/package.json +1 -1
  19. package/prompts/ar.md +81 -48
  20. package/prompts/dist/2d-game.md +1567 -0
  21. package/prompts/dist/3d-app.md +1712 -0
  22. package/prompts/dist/ar-app.md +1585 -0
  23. package/prompts/dist/concept.md +49 -0
  24. package/prompts/dist/design.md +521 -0
  25. package/prompts/dist/ui-app.md +1175 -0
  26. package/prompts/index.md +3 -1
  27. package/src/animate/tween/Timeline.ts +175 -175
  28. package/src/bridges/device.d.ts +20 -6
  29. package/src/bridges/gl.d.ts +33 -19
  30. package/src/compile/header.ts +11 -4
  31. package/src/gl/Camera.ts +5 -2
  32. package/src/gl/CameraPlace.ts +52 -52
  33. package/src/gl/Light.ts +257 -257
  34. package/src/gl/Mesh.ts +120 -120
  35. package/src/gl/Node.ts +0 -8
  36. package/src/gl/Scene.ts +14 -81
  37. package/src/gl/animation/DynamicBone.ts +482 -482
  38. package/src/gl/scenarios.ts +291 -291
  39. package/src/inject.ts +13 -1
  40. package/src/plugin.ts +45 -2
  41. package/src/plugins/gen/ar/contract.d.ts +118 -0
  42. package/src/plugins/gen/ar/sdk/ar.gen.ts +112 -0
  43. package/src/plugins/gen/ar/sdk/ar.ts +699 -0
  44. package/src/plugins/gen/ar/sdk/controls.ts +148 -0
  45. package/src/plugins/gen/audio-recorder/contract.d.ts +64 -0
  46. package/src/plugins/gen/audio-recorder/sdk/audio-recorder.gen.ts +76 -0
  47. package/src/plugins/gen/audio-recorder/sdk/audio-recorder.ts +113 -0
  48. package/src/plugins/gen/geolocation/contract.d.ts +7 -5
  49. package/src/plugins/gen/geolocation/sdk/geolocation.gen.ts +6 -2
  50. package/src/plugins/gen/speech/contract.d.ts +67 -0
  51. package/src/plugins/gen/speech/sdk/speech.gen.ts +64 -0
  52. package/src/plugins/gen/speech/sdk/speech.ts +104 -0
  53. package/src/runtime/permissions.ts +40 -0
  54. package/src/server/auth/host.ts +1 -1
  55. package/src/ui/presentable.ts +5 -0
  56. package/src/ui/router.ts +4 -3
  57. package/src/version.ts +1 -1
  58. package/dist/types/gl/controls.d.ts +0 -19
  59. package/dist/types/plugins/permission.d.ts +0 -1
  60. package/src/gl/controls.ts +0 -95
  61. package/src/plugins/permission.ts +0 -8
package/package.json CHANGED
@@ -45,7 +45,7 @@
45
45
  "marcidb-embedded": "^0.15.0",
46
46
  "sharp": "^0.35.2"
47
47
  },
48
- "version": "2.2.9",
48
+ "version": "2.2.10",
49
49
  "files": [
50
50
  "src",
51
51
  "dist",
package/prompts/ar.md CHANGED
@@ -1,84 +1,119 @@
1
1
  ## AR
2
2
 
3
- ARScene = a scene rendered over the device camera feed with world tracking. Everything from the
4
- 3D-engine section applies (nodes, meshes, models, materials, physics, events); THIS section is how
5
- an AR scene is created and driven. There is no skybox/background (the camera feed shows through),
6
- and lighting still needs the default IBL and/or a Light.sun for lit materials.
3
+ ARScene = a scene over the device camera with world tracking, from the "ar" plugin — the app lists it
4
+ in app.json: `"plugins": { "ar": "*" }` (without it `ARScene.isSupported` is false and open() rejects).
5
+ Everything from the 3D-engine section applies (nodes, meshes, models, materials, physics, events);
6
+ THIS section is how an AR scene is created and driven. The session moves scene.camera every frame and
7
+ draws the camera image behind everything (no skybox shows); lit materials still need the default IBL
8
+ and/or a Light.sun.
7
9
 
8
10
  // ===== ARSCENE =====
9
11
 
10
12
  new ARScene(options?: {
11
13
  ibl?: boolean // image-based ambient light; default TRUE
12
14
  environmentIntensity?: number // IBL strength; default 20000
13
- mode?: 'default' | 'markers' | 'arcore' | 'detached' // tracking mode; default 'default'
15
+ mode?: 'world' | 'images' // 'world' (default): planes, hitTest, anchors, images.
16
+ // 'images': image targets only — no planes, no hitTest, no root
14
17
  })
15
-
16
- await scene.open() // ASYNC (unlike Scene.open): requests camera permission → warm-renders
17
- // → launches tracking. REJECTS if the camera is denied or AR can't
18
- // start — always await and handle failure (fall back / show a message).
19
- scene.close() // stop the AR session
20
- scene.useWarmRender = true // default true — open() pre-compiles shaders itself
18
+ ARScene.isSupported // static: the host has the plugin — check before an AR button
19
+
20
+ await scene.open(options?: { // ASYNC: camera permission → warm render → session → on screen.
21
+ planes?: 'horizontal' | 'vertical' | 'both' | 'none' // default 'horizontal'
22
+ lightEstimation?: boolean // 'light' events
23
+ followLight?: boolean // the scene's ambient follows the estimated light
24
+ transition?: Transition
25
+ }) // REJECTS: camera denied, 'unavailable' (no ARKit/ARCore), superseded —
26
+ // always await and handle failure (fall back / show a message).
27
+ scene.close() // stops the session (the camera is let go)
28
+
29
+ // ===== TRACKING =====
30
+ scene.trackingState // 'notAvailable' | 'limited' | 'normal'
31
+ scene.trackingReason // with 'limited': 'initializing' | 'excessiveMotion' | 'insufficientFeatures' | 'relocalizing'
32
+ scene.addEventListener('tracking', (state, reason) => {})
33
+ scene.addEventListener('error', ({ code, message }) => {}) // the session failed and is over
21
34
 
22
35
  // ===== ANCHORS =====
23
- // An anchor is a Node whose transform is DRIVEN BY TRACKING — parent all content under one.
24
-
25
- scene.root // Node: the world-origin anchor (read-only). NOT available in 'markers' mode.
26
- scene.createAnchor(source: FetchResponse, physicalWidth = 0.2): Node
27
- // Image-target anchor: `source` = the marker image (fetch it), `physicalWidth` = the printed
28
- // target's real-world width in METERS. Add content as children; it appears on the physical image.
29
-
30
- // Tracking state — on any anchor node:
31
- anchor.addEventListener('track', () => {}) // began tracking (marker found / world locked)
32
- anchor.addEventListener('untrack', () => {}) // lost tracking
33
- anchor.isTracked // current state (false for non-anchor nodes)
34
- // Typical: hide content until tracked — anchor.visible = false; on 'track' set true.
36
+ // An Anchor is a Node the session moves — parent content under one (it joins the scene with it).
37
+
38
+ scene.root // Anchor: pinned on the FIRST HORIZONTAL PLANE found ('track' fires then);
39
+ // until then at the world's origin. Not in 'images' mode.
40
+ scene.anchor(pose) // Anchor at a pose ({ position, rotation }, e.g. a hitTest result's)
41
+ scene.createAnchor(source: FetchResponse, physicalWidth = 0.2): ImageAnchor
42
+ // Image target: `source` = the marker image (fetch it), `physicalWidth` = its printed width in
43
+ // METERS. Hidden until the image is seen. A RIGID pose in meters (no scale): its centre, Y out of
44
+ // the image, the image in XZ (Z toward its bottom). Its size: anchor.extent = [width, height] m
45
+ // (refined while tracked; [physicalWidth, 0] before the first 'track'). A plane on it:
46
+ // const s = Mesh.plane({ material, eulerAngles: [-90, 0, 0] }); anchor.add(s)
47
+ // anchor.addEventListener('track', () => s.scale = [anchor.extent[0], anchor.extent[1], 1])
48
+ anchor.tracked // the session holds it now
49
+ anchor.addEventListener('track', () => {})
50
+ anchor.addEventListener('untrack', () => {})
51
+ anchor.remove() // let it go; it leaves the scene
52
+
53
+ // ===== PLANES & HIT TEST =====
54
+ scene.planes // ARPlane[]: plane.type ('horizontal' | 'vertical'), plane.extent [w, d] m,
55
+ // plane.polygon (x,z pairs in the plane's space), plane.center (Vec3)
56
+ scene.addEventListener('plane', ({ plane, change, mergedInto }) => {}) // change: 'added' | 'updated' | 'removed'
57
+ scene.showPlanes = true // a grid drawn on every plane
58
+ const hits = await scene.hitTest(ev.clientX, ev.clientY, 'planes') // a scene touch's point → [{ pose, type, plane, distance }], nearest first; [] = nothing
59
+
60
+ // ===== LIGHT & CAPTURE =====
61
+ scene.lightEstimate // { intensity (1000 = neutral), temperature (K) } | null
62
+ const photo = await scene.captureFrame() // the camera image alone: a JPEG File
63
+ const shot = await scene.capture() // what the scene shows (camera + 3D): a PNG File
35
64
 
36
65
  // ===== PLACEMENT CONTROLS =====
37
- // The standard "place an object in your room" gestures, prebuilt on the public touch API:
38
-
39
66
  const controls = scene.addControls(target: Node, options?: {
40
67
  minScale?: number, // pinch clamp; default 0.08
41
68
  maxScale?: number, // default 2
42
- pan?: boolean, // one-finger drag across the ground plane; default true
69
+ pan?: boolean, // one finger: over the plane under the finger; default true
43
70
  pinch?: boolean, // two-finger uniform scale; default true
44
71
  twist?: boolean, // two-finger rotate around Y; default true
45
72
  })
46
73
  controls.remove() // detach the gesture listeners
47
74
 
75
+ // ===== ON THE WEB =====
76
+ // The camera under the scene, the camera turned by the phone's sensors, its position fixed: tracking
77
+ // is 'normal' at once, NO planes, NO images, hitTest resolves [], root never fires 'track' (it stays
78
+ // at the origin) — don't gate content on root's 'track' if the app must work in a browser.
79
+
48
80
  // ===== AR RULES & MISTAKES =====
49
81
 
50
- // The camera is driven by device tracking — READ it (position, getRay), NEVER place it.
51
- // ❌ moving the camera to frame content — tracking overwrites it every frame
82
+ // The camera is the session's — READ it (position, getRay), NEVER place it.
83
+ // ❌ moving the camera to frame content — the session overwrites it every frame
52
84
  arScene.camera.position = [0, 2, 4]
53
85
  // ✅ move the WORLD: parent content under scene.root (or an anchor) and place THAT
54
86
  scene.root.add(model); model.position = [0, 0, -1]
55
87
 
56
- // ❌ content floating free in scene space without an anchor — it won't stick to the real world
57
- scene.add(model) // added to the draw set but parented to nothing
58
- // ✅ BOTH: parent under an anchor AND register with the scene
59
- scene.root.add(model); scene.add(model)
88
+ // ❌ forgetting the plugin: ARScene without "ar" in app.json "plugins" is unsupported everywhere
89
+ // ✅ app.json: { "plugins": { "ar": "*" } }
60
90
 
61
91
  // ❌ treating open() like Scene.open()
62
- arScene.open(); spawnStuff() // runs before permission is granted; rejection unhandled
63
- // ✅ await it and handle denial
64
- try { await arScene.open() } catch { toast('Camera access is required for AR') }
65
-
66
- // ❌ waiting for content to show without tracking feedback
67
- // ✅ marker apps: keep content hidden until 'track', tell the user to point at the marker
92
+ arScene.open(); spawnStuff() // runs before the session started; rejection unhandled
93
+ // ✅ await it and handle failure
94
+ try { await arScene.open() } catch { toast('AR is not available on this device') }
95
+
96
+ // ❌ placing on a tap at a guessed distance
97
+ // ✅ hitTest the tap and anchor there
98
+ scene.addEventListener('click', async (ev) => {
99
+ const [hit] = await scene.hitTest(ev.clientX, ev.clientY, 'planes')
100
+ if (hit) scene.anchor(hit.pose).add(lamp.clone())
101
+ })
68
102
 
69
103
  // Shadows on the real floor: a Mesh.plane({ normal: [0, 1, 0], material: Material.shadow() })
70
104
  // under the object — invisible except where shadows fall.
71
105
 
72
106
  ## AR example
73
107
 
74
- // Object-placement app: a GLB placed in the room, drag/pinch/twist to position it,
75
- // tap it to play its animation, shadow on the real floor, transparent HUD hint.
108
+ // Object-placement app: a GLB on the floor once it is found, drag/pinch/twist to position it,
109
+ // tap it to play its animation, shadow on the real floor, a HUD hint over the scene.
110
+ // app.json lists the plugin: { "plugins": { "ar": "*" } }
76
111
 
77
112
  <file name="main.ts">
78
113
  const scene = new ARScene()
79
114
 
80
115
  const hint = UIText('Move your phone to find the floor').style({ color: 'white', fontSize: 16 })
81
- const hud = UIScreen(hint).style({ p: 'safe-all', pb: 'comfort-bottom', justifyContent: 'flex-end', alignItems: 'center' })
116
+ scene.widgets(UIWidget(hint).style({ position: 'absolute', left: 0, right: 0, bottom: 48, alignItems: 'center' }))
82
117
 
83
118
  async function main() {
84
119
  const chair = await Model.load(asset('./chair.glb'))
@@ -89,19 +124,17 @@ async function main() {
89
124
  const shadow = Mesh.plane({ normal: [0, 1, 0], material: Material.shadow(), scale: 2 })
90
125
  chair.add(shadow)
91
126
 
92
- // Content lives under the tracked world origin AND in the draw set
93
- chair.position = [0, 0, -1]
127
+ // Content lives under the floor anchor (it joins the scene with it)
94
128
  scene.root.add(chair)
95
- scene.add(chair, shadow, Light.sun({ shadowsQuality: 2 }))
129
+ scene.add(Light.sun({ shadowsQuality: 2 }))
130
+ scene.root.addEventListener('track', () => { hint.text = 'Drag to move · pinch to scale · tap to animate' })
96
131
 
97
132
  scene.addControls(chair) // drag / pinch-scale / twist gestures
98
133
 
99
134
  try {
100
- await scene.open() // camera permission → tracking
101
- hud.open() // transparent HUD over the camera feed
102
- hint.text = 'Drag to move · pinch to scale · tap to animate'
135
+ await scene.open() // camera permission → session
103
136
  } catch {
104
- toast('Camera access is required for AR')
137
+ toast('AR is not available on this device')
105
138
  }
106
139
  }
107
140