lecodes-sdk 1.1.0 → 2.0.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 (257) hide show
  1. package/README.md +5 -2
  2. package/dist/editor.d.ts +12 -0
  3. package/dist/global.d.ts +4 -8
  4. package/dist/host.d.ts +2 -3
  5. package/dist/types/animate/tween/Animation.d.ts +0 -3
  6. package/dist/types/animate/tween/animateValue.d.ts +4 -2
  7. package/dist/types/animate/tween/easing.d.ts +8 -0
  8. package/dist/types/animate/tween/spec.d.ts +15 -7
  9. package/dist/types/audio/audio.d.ts +2 -1
  10. package/dist/types/canvas/Canvas.d.ts +40 -108
  11. package/dist/types/canvas/gen/cssColor.d.ts +17 -0
  12. package/dist/types/canvas/gen/recorder.d.ts +118 -0
  13. package/dist/types/canvas/gen/spec.d.ts +144 -0
  14. package/dist/types/core/color.d.ts +3 -1
  15. package/dist/types/core/pins.d.ts +18 -0
  16. package/dist/types/g2/Node2D.d.ts +5 -8
  17. package/dist/types/g2/Scene2D.d.ts +6 -2
  18. package/dist/types/gl/Foliage.d.ts +30 -7
  19. package/dist/types/gl/Light.d.ts +11 -0
  20. package/dist/types/gl/Lightmap.d.ts +13 -2
  21. package/dist/types/gl/Material.d.ts +17 -3
  22. package/dist/types/gl/Model.d.ts +6 -2
  23. package/dist/types/gl/Node.d.ts +3 -6
  24. package/dist/types/gl/Particles.d.ts +15 -0
  25. package/dist/types/gl/Scene.d.ts +41 -13
  26. package/dist/types/gl/Texture.d.ts +1 -1
  27. package/dist/types/gl/animation/Locomotion.d.ts +59 -3
  28. package/dist/types/gl/terrain/Terrain.d.ts +8 -0
  29. package/dist/types/inject.d.ts +11 -11
  30. package/dist/types/inject.editor.d.ts +1 -0
  31. package/dist/types/net/core.d.ts +7 -0
  32. package/dist/types/plugin.d.ts +76 -0
  33. package/dist/types/plugins/gen/camera/sdk/camera.d.ts +24 -0
  34. package/dist/types/plugins/gen/camera/sdk/camera.gen.d.ts +25 -0
  35. package/dist/types/plugins/{geolocation.d.ts → gen/geolocation/sdk/geolocation.d.ts} +2 -20
  36. package/dist/types/plugins/gen/geolocation/sdk/geolocation.gen.d.ts +31 -0
  37. package/dist/types/plugins/{map.d.ts → gen/map/sdk/map.d.ts} +9 -50
  38. package/dist/types/plugins/gen/map/sdk/map.gen.d.ts +53 -0
  39. package/dist/types/plugins/gen/push/sdk/push.d.ts +23 -0
  40. package/dist/types/plugins/gen/push/sdk/push.gen.d.ts +35 -0
  41. package/dist/types/plugins/{qr.d.ts → gen/qr-scanner/sdk/qr-scanner.d.ts} +2 -3
  42. package/dist/types/plugins/gen/qr-scanner/sdk/qr-scanner.gen.d.ts +15 -0
  43. package/dist/types/runtime/app.d.ts +9 -2
  44. package/dist/types/runtime/fetch.d.ts +2 -0
  45. package/dist/types/runtime/input.d.ts +8 -1
  46. package/dist/types/runtime/media.d.ts +6 -10
  47. package/dist/types/runtime/misc.d.ts +4 -1
  48. package/dist/types/runtime/net.d.ts +3 -2
  49. package/dist/types/runtime/touch.d.ts +32 -0
  50. package/dist/types/scene/defineScene.d.ts +43 -2
  51. package/dist/types/scene/editor.d.ts +52 -0
  52. package/dist/types/scene/gizmos.d.ts +7 -4
  53. package/dist/types/ui/NativeView.d.ts +6 -4
  54. package/dist/types/ui/UI.d.ts +1 -1
  55. package/dist/types/ui/UIBottomSheet.d.ts +6 -12
  56. package/dist/types/ui/UIButton.d.ts +12 -14
  57. package/dist/types/ui/UIContainer.d.ts +0 -6
  58. package/dist/types/ui/UIImage.d.ts +1 -4
  59. package/dist/types/ui/UIInput.d.ts +8 -24
  60. package/dist/types/ui/UIModal.d.ts +0 -2
  61. package/dist/types/ui/UINode.d.ts +70 -56
  62. package/dist/types/ui/UIPager.d.ts +28 -27
  63. package/dist/types/ui/UIPopover.d.ts +0 -2
  64. package/dist/types/ui/UIScreen.d.ts +12 -17
  65. package/dist/types/ui/UIScrollable.d.ts +1 -4
  66. package/dist/types/ui/UIText.d.ts +0 -2
  67. package/dist/types/ui/UIVideo.d.ts +3 -5
  68. package/dist/types/ui/UIVirtualizedList.d.ts +14 -16
  69. package/dist/types/ui/UIWidget.d.ts +10 -9
  70. package/dist/types/ui/colorKeys.gen.d.ts +9 -0
  71. package/dist/types/ui/presentable.d.ts +46 -32
  72. package/dist/types/ui/router.d.ts +18 -7
  73. package/dist/types/ui/styleColor.d.ts +1 -0
  74. package/dist/types/ui/transitions.d.ts +18 -0
  75. package/dist/types/ui/tree.d.ts +75 -0
  76. package/dist/types/version.d.ts +10 -0
  77. package/dist/types.json +1 -1
  78. package/package.json +12 -3
  79. package/prompts/2d.md +2 -6
  80. package/prompts/3d.md +1 -5
  81. package/prompts/README.md +142 -142
  82. package/prompts/canvas.md +9 -8
  83. package/prompts/compose.ts +1 -1
  84. package/prompts/core.md +3 -3
  85. package/prompts/design.md +1 -1
  86. package/prompts/dist/2d-game.md +77 -54
  87. package/prompts/dist/3d-app.md +75 -52
  88. package/prompts/dist/ar-app.md +74 -51
  89. package/prompts/dist/design.md +30 -8
  90. package/prompts/dist/ui-app.md +73 -46
  91. package/prompts/ui-design.md +2 -3
  92. package/prompts/ui.md +45 -37
  93. package/src/animate/tween/Animation.ts +262 -378
  94. package/src/animate/tween/animateValue.ts +103 -100
  95. package/src/animate/tween/easing.ts +10 -3
  96. package/src/animate/tween/spec.ts +505 -479
  97. package/src/audio/Sound.ts +3 -3
  98. package/src/audio/audio.ts +162 -161
  99. package/src/bridges/2d.d.ts +317 -0
  100. package/src/bridges/app.d.ts +91 -0
  101. package/src/bridges/audio.d.ts +97 -0
  102. package/src/bridges/canvas.d.ts +79 -0
  103. package/src/bridges/device.d.ts +72 -0
  104. package/src/bridges/fetch.d.ts +80 -0
  105. package/src/bridges/files.d.ts +70 -0
  106. package/src/bridges/gl.d.ts +1133 -0
  107. package/src/bridges/input.d.ts +72 -0
  108. package/src/bridges/media.d.ts +55 -0
  109. package/src/bridges/nav.d.ts +71 -0
  110. package/src/bridges/net.d.ts +52 -0
  111. package/src/bridges/service.d.ts +52 -0
  112. package/src/bridges/socket.d.ts +31 -0
  113. package/src/bridges/storage.d.ts +33 -0
  114. package/src/bridges/tree.d.ts +301 -0
  115. package/src/bridges/types.d.ts +49 -0
  116. package/src/canvas/Canvas.ts +114 -159
  117. package/src/canvas/gen/cssColor.ts +224 -0
  118. package/src/canvas/gen/recorder.ts +212 -0
  119. package/src/canvas/gen/spec.ts +201 -0
  120. package/src/chisel.ts +193 -0
  121. package/src/compile/assetMacro.ts +1 -1
  122. package/src/compile/bundler.ts +11 -2
  123. package/src/compile/compileProject.ts +43 -4
  124. package/src/compile/fontMacro.ts +3 -4
  125. package/src/compile/header.ts +26 -5
  126. package/src/compile/index.ts +3 -1
  127. package/src/compile/liteMaterial.ts +1 -1
  128. package/src/compile/sceneEditor.ts +11 -26
  129. package/src/core/color.ts +73 -30
  130. package/src/core/pins.ts +51 -0
  131. package/src/core/signals.ts +8 -1
  132. package/src/g2/CharacterController2D.ts +3 -3
  133. package/src/g2/Node2D.ts +57 -39
  134. package/src/g2/Physics2D.ts +2 -2
  135. package/src/g2/Scene2D.ts +35 -23
  136. package/src/g2/Texture2D.ts +1 -1
  137. package/src/g2/loop.ts +4 -4
  138. package/src/gl/Foliage.ts +72 -17
  139. package/src/gl/Geometry.ts +1 -2
  140. package/src/gl/Light.ts +13 -0
  141. package/src/gl/Lightmap.ts +45 -29
  142. package/src/gl/Material.ts +95 -51
  143. package/src/gl/Model.ts +172 -167
  144. package/src/gl/Node.ts +91 -24
  145. package/src/gl/Particles.ts +20 -1
  146. package/src/gl/Scene.ts +100 -44
  147. package/src/gl/Texture.ts +8 -7
  148. package/src/gl/animation/AnimationClip.ts +1 -1
  149. package/src/gl/animation/Locomotion.ts +77 -8
  150. package/src/gl/nav/NavMesh.ts +3 -4
  151. package/src/gl/physics/Physics.ts +2 -2
  152. package/src/gl/physics/physicsEvents.ts +3 -3
  153. package/src/gl/terrain/Terrain.ts +33 -5
  154. package/src/gl/touch.ts +14 -15
  155. package/src/host.d.ts +2 -3
  156. package/src/inject.editor.ts +7 -0
  157. package/src/inject.ts +233 -236
  158. package/src/net/core.ts +6 -5
  159. package/src/net/index.ts +1 -1
  160. package/src/net/replication.ts +1 -1
  161. package/src/plugin.ts +191 -0
  162. package/src/plugins/gen/camera/contract.d.ts +27 -0
  163. package/src/plugins/gen/camera/sdk/camera.gen.ts +46 -0
  164. package/src/plugins/gen/camera/sdk/camera.ts +57 -0
  165. package/src/plugins/gen/geolocation/contract.d.ts +50 -0
  166. package/src/plugins/gen/geolocation/sdk/geolocation.gen.ts +54 -0
  167. package/src/plugins/{geolocation.ts → gen/geolocation/sdk/geolocation.ts} +22 -43
  168. package/src/plugins/gen/map/contract.d.ts +144 -0
  169. package/src/plugins/gen/map/sdk/map.gen.ts +88 -0
  170. package/src/plugins/{map.ts → gen/map/sdk/map.ts} +68 -102
  171. package/src/plugins/gen/push/contract.d.ts +61 -0
  172. package/src/plugins/gen/push/sdk/push.gen.ts +60 -0
  173. package/src/plugins/gen/push/sdk/push.ts +105 -0
  174. package/src/plugins/gen/qr-scanner/contract.d.ts +16 -0
  175. package/src/plugins/gen/qr-scanner/sdk/qr-scanner.gen.ts +29 -0
  176. package/src/plugins/gen/qr-scanner/sdk/qr-scanner.ts +52 -0
  177. package/src/plugins/permission.ts +5 -4
  178. package/src/runtime/app.ts +20 -9
  179. package/src/runtime/appEvents.ts +5 -4
  180. package/src/runtime/channel.ts +18 -15
  181. package/src/runtime/clipboard.ts +4 -3
  182. package/src/runtime/datetime.ts +2 -1
  183. package/src/runtime/device.ts +17 -15
  184. package/src/runtime/fetch.ts +30 -20
  185. package/src/runtime/files.ts +16 -15
  186. package/src/runtime/input.ts +21 -8
  187. package/src/runtime/media.ts +50 -46
  188. package/src/runtime/misc.ts +7 -3
  189. package/src/runtime/net.ts +8 -7
  190. package/src/runtime/rpc.ts +1 -3
  191. package/src/runtime/service.ts +19 -14
  192. package/src/runtime/share.ts +4 -3
  193. package/src/runtime/storage.ts +6 -4
  194. package/src/runtime/touch.ts +32 -0
  195. package/src/scene/defineScene.ts +61 -365
  196. package/src/scene/editor.ts +408 -0
  197. package/src/scene/editorPlugins.ts +3 -3
  198. package/src/scene/gizmos.ts +154 -148
  199. package/src/server/db/marci/query.ts +1 -1
  200. package/src/server/host.ts +1 -1
  201. package/src/server/runtime.ts +1 -1
  202. package/src/ui/NativeView.ts +72 -25
  203. package/src/ui/UI.ts +3 -3
  204. package/src/ui/UIBottomSheet.ts +16 -17
  205. package/src/ui/UIButton.ts +54 -16
  206. package/src/ui/UIContainer.ts +0 -6
  207. package/src/ui/UIImage.ts +34 -30
  208. package/src/ui/UIInput.ts +29 -37
  209. package/src/ui/UIModal.ts +1 -3
  210. package/src/ui/UINode.ts +347 -297
  211. package/src/ui/UIPager.ts +93 -78
  212. package/src/ui/UIPopover.ts +0 -2
  213. package/src/ui/UIScreen.ts +41 -36
  214. package/src/ui/UIScrollable.ts +19 -13
  215. package/src/ui/UISpacer.ts +1 -1
  216. package/src/ui/UITabs.ts +8 -6
  217. package/src/ui/UIText.ts +7 -17
  218. package/src/ui/UIVideo.ts +30 -27
  219. package/src/ui/UIVirtualizedList.ts +58 -59
  220. package/src/ui/UIWidget.ts +38 -18
  221. package/src/ui/colorKeys.gen.ts +37 -0
  222. package/src/ui/fonts.ts +2 -2
  223. package/src/ui/presentable.ts +59 -42
  224. package/src/ui/router.ts +52 -35
  225. package/src/ui/styleColor.ts +56 -0
  226. package/src/ui/theme.ts +7 -6
  227. package/src/ui/transitions.ts +249 -0
  228. package/src/ui/tree.ts +346 -0
  229. package/src/version.ts +24 -0
  230. package/tests/helpers/engineWorld.ts +11 -0
  231. package/tests/helpers/fakeTree.ts +353 -0
  232. package/tests/helpers/hostStubs.ts +31 -0
  233. package/tests/helpers/index.ts +14 -0
  234. package/tests/helpers/memoryMarci.ts +124 -0
  235. package/tests/helpers/phases.ts +23 -0
  236. package/tests/helpers/preload.ts +18 -0
  237. package/tests/helpers/stubApp.ts +2 -0
  238. package/tests/helpers/stubDevice.ts +2 -0
  239. package/tests/helpers/stubFetch.ts +2 -0
  240. package/tests/helpers/stubInput.ts +2 -0
  241. package/dist/inject.js +0 -4730
  242. package/dist/types/core/registry.d.ts +0 -7
  243. package/dist/types/plugins/camera.d.ts +0 -25
  244. package/dist/types/plugins/push.d.ts +0 -46
  245. package/src/bridges.d.ts +0 -1760
  246. package/src/compile/__tests__/assetIconMacro.test.ts +0 -219
  247. package/src/compile/__tests__/assetMacro.test.ts +0 -100
  248. package/src/compile/__tests__/assetName.test.ts +0 -55
  249. package/src/compile/__tests__/compile.test.ts +0 -310
  250. package/src/compile/__tests__/detectEntry.test.ts +0 -151
  251. package/src/compile/__tests__/fontMacro.test.ts +0 -199
  252. package/src/compile/__tests__/serverSplit.test.ts +0 -27
  253. package/src/core/__tests__/stateMachine.test.ts +0 -132
  254. package/src/core/registry.ts +0 -23
  255. package/src/plugins/camera.ts +0 -81
  256. package/src/plugins/push.ts +0 -132
  257. package/src/plugins/qr.ts +0 -73
@@ -1,100 +1,103 @@
1
- // `animate()` — "animate a VALUE, I apply it" (docs/timeline-plan.md): the free-value tween for
2
- // anything without a native writer (a material parameter, a volume, a number the Canvas draws).
3
- // Since 2026-09-14 it runs on the keyframe core like everything else: a VALUE-domain track the host
4
- // evaluates natively and hands back to JS once per frame, the same easing vocabulary, keyframes,
5
- // loops and clocks, and the same `Animation` handle. `Timeline.animate` puts one into a timeline.
6
-
7
- import { TweenAnimation, type Animation } from "./Animation"
8
- import { Mat4 } from "../../math/mat4"
9
- import type { Vec2Like, Vec3Like } from "../../math/vec"
10
- import type { QuatLike } from "../../math/quat"
11
- import type { Mat4Like } from "../../math/mat4"
12
- import type { ColorInput } from "../../core/color"
13
- import {
14
- CLOCK_GAME, CLOCK_UI, DOM_VALUE, KIND_FLOAT, KIND_MAT4, DEFAULT_DURATION_MS, easingFor, iterationsOf, lanesOf, valueValue,
15
- type Keyframe, type Track, type TweenChannel, type TweenMeta, type TweenSpec, type TweenTarget,
16
- } from "./spec"
17
-
18
- /** What `animate()` tweens: a number, a color (string / packed / rgb(a) array — delivered as rgba
19
- * 0..1), a 2 / 3-vector, a quaternion (slerp), or a 4x4 matrix (position / rotation / scale). */
20
- export type AnimateValue = number | string | Vec2Like | Vec3Like | QuatLike | Mat4Like | ColorInput
21
-
22
- /** `onUpdate` receives a number for a number; every other kind arrives as the SAME `Float32Array`
23
- * every frame (overwritten in place — copy it if you keep it). A matrix is the 16 floats. */
24
- export type AnimateOut<T> = T extends number ? number : Float32Array
25
-
26
- export type AnimateOptions<T extends AnimateValue> = Omit<TweenMeta, "commit" | "layer"> & {
27
- /** Start value (required unless `values` is given). */
28
- from?: T,
29
- /** End value. */
30
- to?: T,
31
- /** Keyframes instead of from/to (offsets via `times`). */
32
- values?: T[],
33
- onUpdate(value: AnimateOut<T>): void,
34
- /** After the last frame of a run that reached its end (not on cancel). */
35
- onComplete?(): void,
36
- }
37
-
38
- /** @internal Deliverers turn the host's lanes into the `onUpdate` argument without allocating. */
39
- const deliverer = (kind: number, lanes: number, onUpdate: (v: any) => void): ((l: Float32Array) => void) => {
40
- if (kind === KIND_FLOAT) return (l) => onUpdate(l[0])
41
- if (kind === KIND_MAT4) {
42
- const out = new Float32Array(16)
43
- return (l) => {
44
- const m = Mat4.compose([l[0]!, l[1]!, l[2]!], [l[3]!, l[4]!, l[5]!, l[6]!], [l[7]!, l[8]!, l[9]!]).m
45
- for (let i = 0; i < 16; i++) out[i] = m[i]!
46
- onUpdate(out)
47
- }
48
- }
49
- const out = new Float32Array(lanes)
50
- return (l) => { for (let i = 0; i < lanes; i++) out[i] = l[i]!; onUpdate(out) }
51
- }
52
-
53
- /** VALUE slots are unique per world: the host addresses a value track by (animation, slot), and the
54
- * evaluator must never see two animations naming the same slot (a channel is owned by the newest
55
- * animation that names it — values have no shared state to own). */
56
- let nextSlot = 0
57
-
58
- /** @internal Build a VALUE track from animate options. Returns the track, its deliverer and its slot. */
59
- export const makeValueTrack = (o: AnimateOptions<any>, atMs: number): { track: Track, deliver: (l: Float32Array) => void, slot: number } => {
60
- const slot = ++nextSlot
61
- const raw: unknown[] = o.values ?? (o.from !== undefined && o.to !== undefined ? [o.from, o.to] : [])
62
- if (raw.length < 1) throw new Error("animate: give `from` + `to`, or `values`")
63
- const norm = raw.map((v) => valueValue(v))
64
- if (norm.some((n) => n === null)) throw new Error("animate: a value is not a number, color, vector, quaternion or matrix")
65
- const kind = norm[0]!.kind
66
- if (norm.some((n) => n!.kind !== kind)) throw new Error("animate: every value must be the same kind")
67
- const lanes = lanesOf(kind)
68
- const easing = easingFor(o.easing, "value")
69
- const keys: Keyframe[] = norm.map((n, i) => ({
70
- t: o.times && o.times.length === norm.length ? o.times[i]! : norm.length === 1 ? 1 : i / (norm.length - 1),
71
- easing,
72
- value: { lanes: (n as { lanes: number[] }).lanes },
73
- raw: raw[i],
74
- }))
75
- const channel: TweenChannel = { domain: DOM_VALUE, id: () => slot, value: valueValue }
76
- const target: TweenTarget = { _tweenClock: CLOCK_UI, _tweenChannel: () => channel }
77
- const track: Track = {
78
- target, prop: "value", channel, kind, lanes,
79
- atMs: atMs + (o.delay ?? 0), durMs: Math.max(0, o.duration ?? DEFAULT_DURATION_MS),
80
- commit: false, keys,
81
- }
82
- return { track, deliver: deliverer(kind, lanes, o.onUpdate), slot }
83
- }
84
-
85
- /** Tween a free value and apply it yourself in `onUpdate` — the primitive for anything without a
86
- * native channel (material params, volumes, numbers a Canvas draws). Same easing / keyframes /
87
- * `loop` / `clock` as `animateTo`; returns the {@link Animation} handle. Default clock: `'ui'`. */
88
- export const animate = <T extends AnimateValue>(options: AnimateOptions<T>): Animation => {
89
- const { track, deliver, slot } = makeValueTrack(options, 0)
90
- const spec: TweenSpec = {
91
- clock: options.clock === "game" ? CLOCK_GAME : CLOCK_UI,
92
- durationMs: track.atMs + track.durMs, delayMs: 0,
93
- iterations: iterationsOf(options.loop), pingPong: options.loopMode !== "restart",
94
- rate: 1, tracks: [track], calls: [],
95
- }
96
- const a = new TweenAnimation(spec)
97
- a._values.set(slot, deliver)
98
- if (options.onComplete) a.onFinish((done) => { if (done) options.onComplete!() })
99
- return a.play()
100
- }
1
+ // `animate()` — "animate a VALUE, I apply it" (docs/timeline-plan.md): the free-value tween for
2
+ // anything without a native writer (a material parameter, a volume, a number the Canvas draws).
3
+ // Since 2026-09-14 it runs on the keyframe core like everything else: a VALUE-domain track the host
4
+ // evaluates natively and hands back to JS once per frame, the same easing vocabulary, keyframes,
5
+ // loops and clocks, and the same `Animation` handle. `Timeline.animate` puts one into a timeline.
6
+
7
+ import { LINEAR } from "./easing"
8
+ import { TweenAnimation, type Animation } from "./Animation"
9
+ import { Mat4 } from "../../math/mat4"
10
+ import type { Vec2Like, Vec3Like } from "../../math/vec"
11
+ import type { QuatLike } from "../../math/quat"
12
+ import type { Mat4Like } from "../../math/mat4"
13
+ import type { ColorInput } from "../../core/color"
14
+ import {
15
+ CLOCK_GAME, CLOCK_UI, DOM_VALUE, KIND_FLOAT, KIND_MAT4, DEFAULT_DURATION_MS, easingFor, iterationsOf, lanesOf, valueValue,
16
+ type Keyframe, type Track, type TweenChannel, type TweenMeta, type TweenSpec, type TweenTarget,
17
+ } from "./spec"
18
+
19
+ /** What `animate()` tweens: a number (a FLOAT, never a packed color), a color (any CSS color string,
20
+ * through `Color` — delivered as rgba 0..1; a string that is not a color throws), a 2 / 3-vector (a
21
+ * 3-array is a vector, not a color), a quaternion (slerp), or a 4x4 matrix (position / rotation /
22
+ * scale). */
23
+ export type AnimateValue = number | string | Vec2Like | Vec3Like | QuatLike | Mat4Like | ColorInput
24
+
25
+ /** `onUpdate` receives a number for a number; every other kind arrives as the SAME `Float32Array`
26
+ * every frame (overwritten in place — copy it if you keep it). A matrix is the 16 floats. */
27
+ export type AnimateOut<T> = T extends number ? number : Float32Array
28
+
29
+ export type AnimateOptions<T extends AnimateValue> = Omit<TweenMeta, "commit" | "layer"> & {
30
+ /** Start value (required unless `values` is given). */
31
+ from?: T,
32
+ /** End value. */
33
+ to?: T,
34
+ /** Keyframes instead of from/to (offsets via `times`). */
35
+ values?: T[],
36
+ onUpdate(value: AnimateOut<T>): void,
37
+ /** After the last frame of a run that reached its end (not on cancel). */
38
+ onComplete?(): void,
39
+ }
40
+
41
+ /** @internal Deliverers turn the host's lanes into the `onUpdate` argument without allocating. */
42
+ const deliverer = (kind: number, lanes: number, onUpdate: (v: any) => void): ((l: Float32Array) => void) => {
43
+ if (kind === KIND_FLOAT) return (l) => onUpdate(l[0])
44
+ if (kind === KIND_MAT4) {
45
+ const out = new Float32Array(16)
46
+ return (l) => {
47
+ const m = Mat4.compose([l[0]!, l[1]!, l[2]!], [l[3]!, l[4]!, l[5]!, l[6]!], [l[7]!, l[8]!, l[9]!]).m
48
+ for (let i = 0; i < 16; i++) out[i] = m[i]!
49
+ onUpdate(out)
50
+ }
51
+ }
52
+ const out = new Float32Array(lanes)
53
+ return (l) => { for (let i = 0; i < lanes; i++) out[i] = l[i]!; onUpdate(out) }
54
+ }
55
+
56
+ /** VALUE slots are unique per world: the host addresses a value track by (animation, slot), and the
57
+ * evaluator must never see two animations naming the same slot (a channel is owned by the newest
58
+ * animation that names it — values have no shared state to own). */
59
+ let nextSlot = 0
60
+
61
+ /** @internal Build a VALUE track from animate options. Returns the track, its deliverer and its slot. */
62
+ export const makeValueTrack = (o: AnimateOptions<any>, atMs: number): { track: Track, deliver: (l: Float32Array) => void, slot: number } => {
63
+ const slot = ++nextSlot
64
+ const raw: unknown[] = o.values ?? (o.from !== undefined && o.to !== undefined ? [o.from, o.to] : [])
65
+ if (raw.length < 1) throw new Error("animate: give `from` + `to`, or `values`")
66
+ const norm = raw.map((v) => valueValue(v))
67
+ if (norm.some((n) => n === null)) throw new Error("animate: a value is not a number, color, vector, quaternion or matrix")
68
+ const kind = norm[0]!.kind
69
+ if (norm.some((n) => n!.kind !== kind)) throw new Error("animate: every value must be the same kind")
70
+ const lanes = lanesOf(kind)
71
+ const easing = easingFor(o.easing, "value", LINEAR) // a raw progress: the app maps it, the core never pre-eases it
72
+ const keys: Keyframe[] = norm.map((n, i) => ({
73
+ t: o.times && o.times.length === norm.length ? o.times[i]! : norm.length === 1 ? 1 : i / (norm.length - 1),
74
+ easing,
75
+ value: { lanes: (n as { lanes: number[] }).lanes },
76
+ raw: raw[i],
77
+ }))
78
+ const channel: TweenChannel = { domain: DOM_VALUE, id: () => slot, value: valueValue }
79
+ const target: TweenTarget = { _tweenClock: CLOCK_UI, _tweenChannel: () => channel }
80
+ const track: Track = {
81
+ target, prop: "value", channel, kind, lanes,
82
+ atMs: atMs + (o.delay ?? 0), durMs: Math.max(0, o.duration ?? DEFAULT_DURATION_MS),
83
+ commit: false, keys,
84
+ }
85
+ return { track, deliver: deliverer(kind, lanes, o.onUpdate), slot }
86
+ }
87
+
88
+ /** Tween a free value and apply it yourself in `onUpdate` — the primitive for anything without a
89
+ * native channel (material params, volumes, numbers a Canvas draws). Same easing / keyframes /
90
+ * `loop` / `clock` as `animateTo`; returns the {@link Animation} handle. Default clock: `'ui'`. */
91
+ export const animate = <T extends AnimateValue>(options: AnimateOptions<T>): Animation => {
92
+ const { track, deliver, slot } = makeValueTrack(options, 0)
93
+ const spec: TweenSpec = {
94
+ clock: options.clock === "game" ? CLOCK_GAME : CLOCK_UI,
95
+ durationMs: track.atMs + track.durMs, delayMs: 0,
96
+ iterations: iterationsOf(options.loop), pingPong: options.loopMode !== "restart",
97
+ rate: 1, tracks: [track], calls: [],
98
+ }
99
+ const a = new TweenAnimation(spec)
100
+ a._values.set(slot, deliver)
101
+ if (options.onComplete) a.onFinish((done) => { if (done) options.onComplete!() })
102
+ return a.play()
103
+ }
@@ -75,7 +75,7 @@ export const NAMED_EASINGS: ReadonlyArray<readonly [string, Easing]> = [
75
75
  ["inBounce", (x) => 1 - outBounce(1 - x)], // 25
76
76
  ["outBounce", outBounce], // 26
77
77
  ["inOutBounce", (x) => (x < 0.5 ? (1 - outBounce(1 - 2 * x)) / 2 : (1 + outBounce(2 * x - 1)) / 2)], // 27
78
- ["smoothstep", (x) => x * x * (3 - 2 * x)], // 28 — the $class / onPressed default
78
+ ["smoothstep", (x) => x * x * (3 - 2 * x)], // 28 — the $class block default
79
79
  ]
80
80
 
81
81
  /** Short spellings → canonical names. `in`/`out`/`inOut` are the quadratics, matching the SDK's
@@ -94,8 +94,15 @@ const namedId = (name: string): number => {
94
94
 
95
95
  /** The CSS `ease` curve — what a bare `"ease"` means. */
96
96
  const CSS_EASE: [number, number, number, number] = [0.25, 0.1, 0.25, 1]
97
-
98
- const LINEAR: EasingSpec = { kind: EASE_LINEAR, p: [0, 0, 0, 0] }
97
+ /** The CSS `ease-in-out` curve — also UIKit's default animation curve, and web-lite's transition
98
+ * default: what every host tweened with before the keyframe core. */
99
+ export const CSS_EASE_IN_OUT: [number, number, number, number] = [0.42, 0, 0.58, 1]
100
+
101
+ export const LINEAR: EasingSpec = { kind: EASE_LINEAR, p: [0, 0, 0, 0] }
102
+ /** The default of every track with a TARGET (`animateTo` / `animateFrom` / `Timeline.add` on an
103
+ * element, a 3D / 2D object): `ease-in-out` (2026-09-27; linear before). `animate()` — a raw
104
+ * progress the app maps itself — stays linear. Write `easing: "linear"` for uniform motion. */
105
+ export const DEFAULT_EASING: EasingSpec = { kind: EASE_BEZIER, p: CSS_EASE_IN_OUT }
99
106
 
100
107
  /** Sample an `Easing` function into a table. Endpoints are forced exact so a curve that is
101
108
  * numerically 0.9999 at 1 still lands on the keyframe. */