lecodes-sdk 1.0.0 → 1.2.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 (94) hide show
  1. package/dist/global.d.ts +18 -4
  2. package/dist/inject.js +260 -361
  3. package/dist/types/animate/tween/Animation.d.ts +69 -0
  4. package/dist/types/animate/tween/Timeline.d.ts +55 -0
  5. package/dist/types/animate/tween/animateValue.d.ts +27 -0
  6. package/dist/types/animate/tween/easing.d.ts +29 -0
  7. package/dist/types/animate/tween/spec.d.ts +178 -0
  8. package/dist/types/g2/Node2D.d.ts +16 -0
  9. package/dist/types/g2/Sprite.d.ts +11 -1
  10. package/dist/types/gl/Camera.d.ts +15 -1
  11. package/dist/types/gl/Foliage.d.ts +47 -0
  12. package/dist/types/gl/Geometry.d.ts +24 -0
  13. package/dist/types/gl/Light.d.ts +28 -7
  14. package/dist/types/gl/Lightmap.d.ts +90 -60
  15. package/dist/types/gl/Material.d.ts +28 -20
  16. package/dist/types/gl/Model.d.ts +7 -5
  17. package/dist/types/gl/Node.d.ts +18 -0
  18. package/dist/types/gl/Particles.d.ts +55 -1
  19. package/dist/types/gl/Scene.d.ts +20 -0
  20. package/dist/types/gl/animation/AnimationClip.d.ts +19 -0
  21. package/dist/types/gl/animation/Animator.d.ts +27 -0
  22. package/dist/types/gl/animation/DynamicBone.d.ts +19 -8
  23. package/dist/types/gl/animation/IK.d.ts +86 -30
  24. package/dist/types/gl/animation/Locomotion.d.ts +52 -3
  25. package/dist/types/gl/animation/Warp.d.ts +2 -1
  26. package/dist/types/gl/animation/core.d.ts +35 -4
  27. package/dist/types/gl/physics/Ragdoll.d.ts +87 -12
  28. package/dist/types/gl/terrain/Terrain.d.ts +12 -2
  29. package/dist/types/inject.d.ts +8 -2
  30. package/dist/types/runtime/input.d.ts +7 -0
  31. package/dist/types/scene/defineScene.d.ts +44 -32
  32. package/dist/types/ui/UIButton.d.ts +3 -1
  33. package/dist/types/ui/UIInput.d.ts +5 -1
  34. package/dist/types/ui/UINode.d.ts +24 -24
  35. package/dist/types.json +1 -1
  36. package/package.json +1 -1
  37. package/prompts/README.md +142 -142
  38. package/prompts/core-design.md +27 -4
  39. package/prompts/core.md +35 -6
  40. package/prompts/dist/2d-game.md +197 -408
  41. package/prompts/dist/3d-app.md +166 -491
  42. package/prompts/dist/ar-app.md +163 -373
  43. package/prompts/dist/design.md +87 -83
  44. package/prompts/dist/ui-app.md +136 -325
  45. package/prompts/select.ts +19 -4
  46. package/src/animate/tween/Animation.ts +378 -0
  47. package/src/animate/tween/Timeline.ts +175 -0
  48. package/src/animate/tween/animateValue.ts +100 -0
  49. package/src/animate/tween/easing.ts +172 -0
  50. package/src/animate/tween/spec.ts +479 -0
  51. package/src/audio/audio.ts +161 -161
  52. package/src/bridges.d.ts +235 -65
  53. package/src/compile/__tests__/assetMacro.test.ts +26 -0
  54. package/src/compile/__tests__/detectEntry.test.ts +19 -0
  55. package/src/compile/__tests__/serverSplit.test.ts +27 -0
  56. package/src/compile/bundler.ts +34 -4
  57. package/src/compile/compileProject.ts +31 -1
  58. package/src/compile/detectEntry.ts +8 -3
  59. package/src/compile/index.ts +2 -0
  60. package/src/compile/serverSplit.ts +9 -3
  61. package/src/g2/Node2D.ts +38 -0
  62. package/src/g2/Sprite.ts +20 -1
  63. package/src/gl/Camera.ts +34 -1
  64. package/src/gl/CameraPlace.ts +52 -52
  65. package/src/gl/Foliage.ts +102 -0
  66. package/src/gl/Geometry.ts +393 -348
  67. package/src/gl/Light.ts +49 -16
  68. package/src/gl/Lightmap.ts +439 -275
  69. package/src/gl/Material.ts +59 -47
  70. package/src/gl/Mesh.ts +120 -120
  71. package/src/gl/Model.ts +23 -12
  72. package/src/gl/Node.ts +39 -0
  73. package/src/gl/Particles.ts +80 -2
  74. package/src/gl/Scene.ts +34 -1
  75. package/src/gl/animation/AnimationClip.ts +52 -0
  76. package/src/gl/animation/Animator.ts +42 -2
  77. package/src/gl/animation/DynamicBone.ts +35 -12
  78. package/src/gl/animation/IK.ts +173 -152
  79. package/src/gl/animation/Locomotion.ts +72 -8
  80. package/src/gl/animation/Playback.ts +5 -4
  81. package/src/gl/animation/Warp.ts +5 -2
  82. package/src/gl/animation/core.ts +65 -4
  83. package/src/gl/physics/Ragdoll.ts +451 -272
  84. package/src/gl/scenarios.ts +291 -291
  85. package/src/gl/terrain/Terrain.ts +33 -2
  86. package/src/inject.ts +236 -226
  87. package/src/runtime/input.ts +11 -0
  88. package/src/scene/defineScene.ts +72 -62
  89. package/src/scene/gizmos.ts +148 -148
  90. package/src/ui/UIButton.ts +2 -2
  91. package/src/ui/UIInput.ts +3 -3
  92. package/src/ui/UINode.ts +61 -36
  93. package/dist/types/animate/animate.d.ts +0 -20
  94. package/src/animate/animate.ts +0 -238
@@ -1,161 +1,161 @@
1
- // The `audio` global (docs/audio-plan.md §2): 2D playback, one-shots at a world point, buses.
2
- // 3D playback from a node goes through the AudioSource aspect (gl/AudioSource.ts), which calls
3
- // back into `_play` here with its source id; the listener lives on `scene.audio`.
4
- //
5
- // audio.play(click, { bus: 'ui' })
6
- // audio.playAt(impact, hit.point, { maxDistance: 25 })
7
- // audio.bus('sfx').reverb = 'cave'
8
- // audio.stopAll(0.2)
9
-
10
- import { cx, cy, cz, type Vec3Like } from "../math/vec"
11
- import { Bus } from "./Bus"
12
- import type { Sound } from "./Sound"
13
- import { audioSupported } from "./support"
14
- import { Voice } from "./Voice"
15
-
16
- export type PlaySoundOptions = {
17
- /** 0 … 1 (and above, at your own risk). Default 1. */
18
- volume?: number
19
- /** Playback rate, 1 = unchanged. Default 1. */
20
- pitch?: number
21
- loop?: boolean
22
- /** Bus name; default: the source's bus, `sfx` for 2D. */
23
- bus?: string
24
- /** Higher survives voice stealing when the pool is full. Default 0. */
25
- priority?: number
26
- /** Fade-in seconds. Default 0. */
27
- fade?: number
28
- /** Seconds into the clip to start from. */
29
- startAt?: number
30
- /** 2D only: -1 left … 1 right. */
31
- pan?: number
32
- }
33
-
34
- export type Rolloff = "none" | "inverse" | "linear" | "exponential"
35
-
36
- /** Distance model of an AudioSource / playAt. */
37
- export type SpatialOptions = {
38
- /** Metres of full volume around the source. Default 1. */
39
- minDistance?: number
40
- /** Metres beyond which the source no longer gets quieter. Default 50. */
41
- maxDistance?: number
42
- /** How volume falls between the two: `inverse` (default, physical), `linear`, `exponential`, `none`. */
43
- rolloff?: Rolloff
44
- }
45
-
46
- export const ROLLOFF: Record<Rolloff, number> = { none: 0, inverse: 1, linear: 2, exponential: 3 }
47
-
48
- /** @internal CAUD_SRC_* order. */
49
- export function sourceParams(o: { minDistance: number, maxDistance: number, rolloff: Rolloff, coneInner: number, coneOuter: number, coneOuterGain: number, doppler: number, spread: number, occlusion: boolean, bus: number }): Float32Array {
50
- return new Float32Array([ o.minDistance, o.maxDistance, ROLLOFF[o.rolloff] ?? 1, o.coneInner, o.coneOuter, o.coneOuterGain, o.doppler, o.spread, o.occlusion ? 1 : 0, o.bus ])
51
- }
52
-
53
- export type AudioStats = {
54
- voicesPlaying: number
55
- voicesMono: number
56
- voicesStereo: number
57
- /** Voices displaced (or dropped) by a fuller pool since start. */
58
- stolen: number
59
- clips: number
60
- clipBytes: number
61
- /** Master peak since the previous read, linear (1 = full scale). */
62
- peak: number
63
- sampleRate: number
64
- /** The reverb zone the listener is in (0 = none) and how far inside (0 … 1). */
65
- listenerZone: number
66
- zoneBlend: number
67
- /** Voices rendered binaurally right now (see `audio.hrtf`). */
68
- hrtfVoices: number
69
- }
70
-
71
- const DEFAULT_BUSES = [ "master", "sfx", "music", "ui", "voice" ]
72
-
73
- class AudioSystem {
74
- private readonly _buses = new Map<string, Bus>()
75
- private _hrtf = false
76
- private _hrtfVoices = 16
77
- private _timeScalePitch = false
78
-
79
- /** True when this host mixes sound. Everything below is a silent no-op otherwise. */
80
- get supported(): boolean { return audioSupported }
81
-
82
- /** HRTF binaural rendering (MIT KEMAR filters on the CPU): sounds get a real up / down / behind in
83
- * HEADPHONES. Off by default — on speakers it only smears the image. Applies to the `hrtfVoices`
84
- * nearest 3D voices; the rest keep plain panning. */
85
- get hrtf(): boolean { return this._hrtf }
86
- set hrtf(v: boolean) { this._hrtf = v; if (audioSupported) _creatorAudio.setHrtf(v, this._hrtfVoices) }
87
- /** `Time.scale` also pitches the sfx bus: slow motion drops every effect's tone, like a film. Default
88
- * false — a pause only mutes sfx, the menu click keeps its pitch. */
89
- get timeScalePitch(): boolean { return this._timeScalePitch }
90
- set timeScalePitch(v: boolean) { this._timeScalePitch = v; if (audioSupported) _creatorAudio.setTimeScalePitch(v) }
91
- /** How many voices get the (CPU-heavier) binaural path. Default 16. */
92
- get hrtfVoices(): number { return this._hrtfVoices }
93
- set hrtfVoices(n: number) { this._hrtfVoices = n; if (audioSupported && this._hrtf) _creatorAudio.setHrtf(true, n) }
94
-
95
- /** A bus by name — the five built-ins, or an app-defined one created on first use. */
96
- bus(name: string): Bus {
97
- let b = this._buses.get(name)
98
- if (b) return b
99
- let id = -1
100
- if (audioSupported) {
101
- id = _creatorAudio.busId(name)
102
- if (id < 0 && !DEFAULT_BUSES.includes(name)) id = _creatorAudio.createBus(name)
103
- if (id < 0) console.warn(`audio.bus('${name}'): no free bus slot (16 max)`)
104
- }
105
- b = new Bus(name, id)
106
- this._buses.set(name, b)
107
- return b
108
- }
109
- get master(): Bus { return this.bus("master") }
110
-
111
- /** @internal the bus id for an options object (or -1 = the source's). */
112
- _busId(name: string | undefined): number {
113
- if (name === undefined) return -1
114
- return this.bus(name)._id
115
- }
116
-
117
- /** 2D playback (UI, stingers, music one-shots). */
118
- play(sound: Sound, options: PlaySoundOptions = {}): Voice {
119
- return this._play(sound, 0, options)
120
- }
121
-
122
- /** A one-shot at a world position with its own transient source — impacts, ricochets, debris.
123
- * The source is freed when the voice ends. */
124
- playAt(sound: Sound, position: Vec3Like, options: PlaySoundOptions & SpatialOptions = {}): Voice {
125
- if (!audioSupported || !sound.ready) return new Voice(0, options.volume ?? 1, options.pitch ?? 1, 0)
126
- const src = _creatorAudio.createSource()
127
- _creatorAudio.setSourceParams(src, sourceParams({
128
- minDistance: options.minDistance ?? 1, maxDistance: options.maxDistance ?? 50, rolloff: options.rolloff ?? "inverse",
129
- coneInner: 360, coneOuter: 360, coneOuterGain: 1, doppler: 0, spread: 0, occlusion: false, bus: this._busId(options.bus ?? "sfx"),
130
- }))
131
- _creatorAudio.setSourcePosition(src, cx(position), cy(position), cz(position))
132
- const v = this._play(sound, src, options)
133
- if (v._tok === 0) { _creatorAudio.destroySource(src); return v }
134
- v._ownSource = src
135
- v._watch()
136
- return v
137
- }
138
-
139
- /** @internal shared by play / playAt / AudioSource.play. */
140
- _play(sound: Sound, sourceId: number, options: PlaySoundOptions): Voice {
141
- const volume = options.volume ?? 1, pitch = options.pitch ?? 1, pan = options.pan ?? 0
142
- if (!audioSupported || !sound.ready) return new Voice(0, volume, pitch, pan)
143
- const clip = sound._pick()
144
- if (clip === 0) return new Voice(0, volume, pitch, pan)
145
- const tok = _creatorAudio.play(clip, sourceId, this._busId(options.bus), volume, pitch, !!options.loop,
146
- options.priority ?? 0, options.fade ?? 0, options.startAt ?? 0, pan)
147
- return new Voice(tok, volume, pitch, pan)
148
- }
149
-
150
- /** Stop every voice on every bus (fade in seconds). */
151
- stopAll(fade = 0): void { if (audioSupported) _creatorAudio.stopAll(fade) }
152
-
153
- /** Engine counters for a debug overlay or a perf log. */
154
- get stats(): AudioStats {
155
- const s = audioSupported ? _creatorAudio.stats() : new Float32Array(11)
156
- return { voicesPlaying: s[0], voicesMono: s[1], voicesStereo: s[2], stolen: s[3], clips: s[4], clipBytes: s[5], peak: s[6], sampleRate: s[7], listenerZone: s[8], zoneBlend: s[9], hrtfVoices: s[10] ?? 0 }
157
- }
158
- }
159
-
160
- export const audio = new AudioSystem()
161
- export type { AudioSystem }
1
+ // The `audio` global (docs/audio-plan.md §2): 2D playback, one-shots at a world point, buses.
2
+ // 3D playback from a node goes through the AudioSource aspect (gl/AudioSource.ts), which calls
3
+ // back into `_play` here with its source id; the listener lives on `scene.audio`.
4
+ //
5
+ // audio.play(click, { bus: 'ui' })
6
+ // audio.playAt(impact, hit.point, { maxDistance: 25 })
7
+ // audio.bus('sfx').reverb = 'cave'
8
+ // audio.stopAll(0.2)
9
+
10
+ import { cx, cy, cz, type Vec3Like } from "../math/vec"
11
+ import { Bus } from "./Bus"
12
+ import type { Sound } from "./Sound"
13
+ import { audioSupported } from "./support"
14
+ import { Voice } from "./Voice"
15
+
16
+ export type PlaySoundOptions = {
17
+ /** 0 … 1 (and above, at your own risk). Default 1. */
18
+ volume?: number
19
+ /** Playback rate, 1 = unchanged. Default 1. */
20
+ pitch?: number
21
+ loop?: boolean
22
+ /** Bus name; default: the source's bus, `sfx` for 2D. */
23
+ bus?: string
24
+ /** Higher survives voice stealing when the pool is full. Default 0. */
25
+ priority?: number
26
+ /** Fade-in seconds. Default 0. */
27
+ fade?: number
28
+ /** Seconds into the clip to start from. */
29
+ startAt?: number
30
+ /** 2D only: -1 left … 1 right. */
31
+ pan?: number
32
+ }
33
+
34
+ export type Rolloff = "none" | "inverse" | "linear" | "exponential"
35
+
36
+ /** Distance model of an AudioSource / playAt. */
37
+ export type SpatialOptions = {
38
+ /** Metres of full volume around the source. Default 1. */
39
+ minDistance?: number
40
+ /** Metres beyond which the source no longer gets quieter. Default 50. */
41
+ maxDistance?: number
42
+ /** How volume falls between the two: `inverse` (default, physical), `linear`, `exponential`, `none`. */
43
+ rolloff?: Rolloff
44
+ }
45
+
46
+ export const ROLLOFF: Record<Rolloff, number> = { none: 0, inverse: 1, linear: 2, exponential: 3 }
47
+
48
+ /** @internal CAUD_SRC_* order. */
49
+ export function sourceParams(o: { minDistance: number, maxDistance: number, rolloff: Rolloff, coneInner: number, coneOuter: number, coneOuterGain: number, doppler: number, spread: number, occlusion: boolean, bus: number }): Float32Array {
50
+ return new Float32Array([ o.minDistance, o.maxDistance, ROLLOFF[o.rolloff] ?? 1, o.coneInner, o.coneOuter, o.coneOuterGain, o.doppler, o.spread, o.occlusion ? 1 : 0, o.bus ])
51
+ }
52
+
53
+ export type AudioStats = {
54
+ voicesPlaying: number
55
+ voicesMono: number
56
+ voicesStereo: number
57
+ /** Voices displaced (or dropped) by a fuller pool since start. */
58
+ stolen: number
59
+ clips: number
60
+ clipBytes: number
61
+ /** Master peak since the previous read, linear (1 = full scale). */
62
+ peak: number
63
+ sampleRate: number
64
+ /** The reverb zone the listener is in (0 = none) and how far inside (0 … 1). */
65
+ listenerZone: number
66
+ zoneBlend: number
67
+ /** Voices rendered binaurally right now (see `audio.hrtf`). */
68
+ hrtfVoices: number
69
+ }
70
+
71
+ const DEFAULT_BUSES = [ "master", "sfx", "music", "ui", "voice" ]
72
+
73
+ class AudioSystem {
74
+ private readonly _buses = new Map<string, Bus>()
75
+ private _hrtf = false
76
+ private _hrtfVoices = 16
77
+ private _timeScalePitch = false
78
+
79
+ /** True when this host mixes sound. Everything below is a silent no-op otherwise. */
80
+ get supported(): boolean { return audioSupported }
81
+
82
+ /** HRTF binaural rendering (MIT KEMAR filters on the CPU): sounds get a real up / down / behind in
83
+ * HEADPHONES. Off by default — on speakers it only smears the image. Applies to the `hrtfVoices`
84
+ * nearest 3D voices; the rest keep plain panning. */
85
+ get hrtf(): boolean { return this._hrtf }
86
+ set hrtf(v: boolean) { this._hrtf = v; if (audioSupported) _creatorAudio.setHrtf(v, this._hrtfVoices) }
87
+ /** `Time.scale` also pitches the sfx bus: slow motion drops every effect's tone, like a film. Default
88
+ * false — a pause only mutes sfx, the menu click keeps its pitch. */
89
+ get timeScalePitch(): boolean { return this._timeScalePitch }
90
+ set timeScalePitch(v: boolean) { this._timeScalePitch = v; if (audioSupported) _creatorAudio.setTimeScalePitch(v) }
91
+ /** How many voices get the (CPU-heavier) binaural path. Default 16. */
92
+ get hrtfVoices(): number { return this._hrtfVoices }
93
+ set hrtfVoices(n: number) { this._hrtfVoices = n; if (audioSupported && this._hrtf) _creatorAudio.setHrtf(true, n) }
94
+
95
+ /** A bus by name — the five built-ins, or an app-defined one created on first use. */
96
+ bus(name: string): Bus {
97
+ let b = this._buses.get(name)
98
+ if (b) return b
99
+ let id = -1
100
+ if (audioSupported) {
101
+ id = _creatorAudio.busId(name)
102
+ if (id < 0 && !DEFAULT_BUSES.includes(name)) id = _creatorAudio.createBus(name)
103
+ if (id < 0) console.warn(`audio.bus('${name}'): no free bus slot (16 max)`)
104
+ }
105
+ b = new Bus(name, id)
106
+ this._buses.set(name, b)
107
+ return b
108
+ }
109
+ get master(): Bus { return this.bus("master") }
110
+
111
+ /** @internal the bus id for an options object (or -1 = the source's). */
112
+ _busId(name: string | undefined): number {
113
+ if (name === undefined) return -1
114
+ return this.bus(name)._id
115
+ }
116
+
117
+ /** 2D playback (UI, stingers, music one-shots). */
118
+ play(sound: Sound, options: PlaySoundOptions = {}): Voice {
119
+ return this._play(sound, 0, options)
120
+ }
121
+
122
+ /** A one-shot at a world position with its own transient source — impacts, ricochets, debris.
123
+ * The source is freed when the voice ends. */
124
+ playAt(sound: Sound, position: Vec3Like, options: PlaySoundOptions & SpatialOptions = {}): Voice {
125
+ if (!audioSupported || !sound.ready) return new Voice(0, options.volume ?? 1, options.pitch ?? 1, 0)
126
+ const src = _creatorAudio.createSource()
127
+ _creatorAudio.setSourceParams(src, sourceParams({
128
+ minDistance: options.minDistance ?? 1, maxDistance: options.maxDistance ?? 50, rolloff: options.rolloff ?? "inverse",
129
+ coneInner: 360, coneOuter: 360, coneOuterGain: 1, doppler: 0, spread: 0, occlusion: false, bus: this._busId(options.bus ?? "sfx"),
130
+ }))
131
+ _creatorAudio.setSourcePosition(src, cx(position), cy(position), cz(position))
132
+ const v = this._play(sound, src, options)
133
+ if (v._tok === 0) { _creatorAudio.destroySource(src); return v }
134
+ v._ownSource = src
135
+ v._watch()
136
+ return v
137
+ }
138
+
139
+ /** @internal shared by play / playAt / AudioSource.play. */
140
+ _play(sound: Sound, sourceId: number, options: PlaySoundOptions): Voice {
141
+ const volume = options.volume ?? 1, pitch = options.pitch ?? 1, pan = options.pan ?? 0
142
+ if (!audioSupported || !sound.ready) return new Voice(0, volume, pitch, pan)
143
+ const clip = sound._pick()
144
+ if (clip === 0) return new Voice(0, volume, pitch, pan)
145
+ const tok = _creatorAudio.play(clip, sourceId, this._busId(options.bus), volume, pitch, !!options.loop,
146
+ options.priority ?? 0, options.fade ?? 0, options.startAt ?? 0, pan)
147
+ return new Voice(tok, volume, pitch, pan)
148
+ }
149
+
150
+ /** Stop every voice on every bus (fade in seconds). */
151
+ stopAll(fade = 0): void { if (audioSupported) _creatorAudio.stopAll(fade) }
152
+
153
+ /** Engine counters for a debug overlay or a perf log. */
154
+ get stats(): AudioStats {
155
+ const s = audioSupported ? _creatorAudio.stats() : new Float32Array(11)
156
+ return { voicesPlaying: s[0], voicesMono: s[1], voicesStereo: s[2], stolen: s[3], clips: s[4], clipBytes: s[5], peak: s[6], sampleRate: s[7], listenerZone: s[8], zoneBlend: s[9], hrtfVoices: s[10] ?? 0 }
157
+ }
158
+ }
159
+
160
+ export const audio = new AudioSystem()
161
+ export type { AudioSystem }