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.
- package/dist/global.d.ts +42 -1
- package/dist/types/gl/Camera.d.ts +5 -2
- package/dist/types/gl/Node.d.ts +0 -7
- package/dist/types/gl/Scene.d.ts +6 -24
- package/dist/types/inject.d.ts +5 -1
- package/dist/types/plugin.d.ts +27 -0
- package/dist/types/plugins/gen/ar/sdk/ar.d.ts +228 -0
- package/dist/types/plugins/gen/ar/sdk/ar.gen.d.ts +73 -0
- package/dist/types/plugins/gen/ar/sdk/controls.d.ts +28 -0
- package/dist/types/plugins/gen/audio-recorder/sdk/audio-recorder.d.ts +43 -0
- package/dist/types/plugins/gen/audio-recorder/sdk/audio-recorder.gen.d.ts +47 -0
- package/dist/types/plugins/gen/geolocation/sdk/geolocation.gen.d.ts +6 -2
- package/dist/types/plugins/gen/speech/sdk/speech.d.ts +44 -0
- package/dist/types/plugins/gen/speech/sdk/speech.gen.d.ts +39 -0
- package/dist/types/runtime/permissions.d.ts +16 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types.json +1 -1
- package/package.json +1 -1
- package/prompts/ar.md +81 -48
- package/prompts/dist/2d-game.md +1567 -0
- package/prompts/dist/3d-app.md +1712 -0
- package/prompts/dist/ar-app.md +1585 -0
- package/prompts/dist/concept.md +49 -0
- package/prompts/dist/design.md +521 -0
- package/prompts/dist/ui-app.md +1175 -0
- package/prompts/index.md +3 -1
- package/src/animate/tween/Timeline.ts +175 -175
- package/src/bridges/device.d.ts +20 -6
- package/src/bridges/gl.d.ts +33 -19
- package/src/compile/header.ts +11 -4
- package/src/gl/Camera.ts +5 -2
- package/src/gl/CameraPlace.ts +52 -52
- package/src/gl/Light.ts +257 -257
- package/src/gl/Mesh.ts +120 -120
- package/src/gl/Node.ts +0 -8
- package/src/gl/Scene.ts +14 -81
- package/src/gl/animation/DynamicBone.ts +482 -482
- package/src/gl/scenarios.ts +291 -291
- package/src/inject.ts +13 -1
- package/src/plugin.ts +45 -2
- package/src/plugins/gen/ar/contract.d.ts +118 -0
- package/src/plugins/gen/ar/sdk/ar.gen.ts +112 -0
- package/src/plugins/gen/ar/sdk/ar.ts +699 -0
- package/src/plugins/gen/ar/sdk/controls.ts +148 -0
- package/src/plugins/gen/audio-recorder/contract.d.ts +64 -0
- package/src/plugins/gen/audio-recorder/sdk/audio-recorder.gen.ts +76 -0
- package/src/plugins/gen/audio-recorder/sdk/audio-recorder.ts +113 -0
- package/src/plugins/gen/geolocation/contract.d.ts +7 -5
- package/src/plugins/gen/geolocation/sdk/geolocation.gen.ts +6 -2
- package/src/plugins/gen/speech/contract.d.ts +67 -0
- package/src/plugins/gen/speech/sdk/speech.gen.ts +64 -0
- package/src/plugins/gen/speech/sdk/speech.ts +104 -0
- package/src/runtime/permissions.ts +40 -0
- package/src/server/auth/host.ts +1 -1
- package/src/ui/presentable.ts +5 -0
- package/src/ui/router.ts +4 -3
- package/src/version.ts +1 -1
- package/dist/types/gl/controls.d.ts +0 -19
- package/dist/types/plugins/permission.d.ts +0 -1
- package/src/gl/controls.ts +0 -95
- package/src/plugins/permission.ts +0 -8
package/package.json
CHANGED
package/prompts/ar.md
CHANGED
|
@@ -1,84 +1,119 @@
|
|
|
1
1
|
## AR
|
|
2
2
|
|
|
3
|
-
ARScene = a scene
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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?: '
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
24
|
-
|
|
25
|
-
scene.root //
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
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
|
|
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
|
|
51
|
-
// ❌ moving the camera to frame content —
|
|
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
|
-
// ❌
|
|
57
|
-
|
|
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
|
|
63
|
-
// ✅ await it and handle
|
|
64
|
-
try { await arScene.open() } catch { toast('
|
|
65
|
-
|
|
66
|
-
// ❌
|
|
67
|
-
// ✅
|
|
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
|
|
75
|
-
// tap it to play its animation, shadow on the real floor,
|
|
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
|
-
|
|
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
|
|
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(
|
|
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 →
|
|
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('
|
|
137
|
+
toast('AR is not available on this device')
|
|
105
138
|
}
|
|
106
139
|
}
|
|
107
140
|
|