lecodes-cli 0.18.2 → 0.19.2

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 (224) hide show
  1. package/dist/index.js +1866 -301
  2. package/package.json +14 -12
  3. package/runtime/scene-harness.json +1 -1
  4. package/runtime/sdk-types.json +1 -1
  5. package/src/api.ts +302 -0
  6. package/src/browserAuth.ts +87 -0
  7. package/src/cmgenTool.ts +104 -0
  8. package/src/commands/app.ts +891 -0
  9. package/src/commands/appAndroid.ts +603 -0
  10. package/src/commands/appDesktop.ts +326 -0
  11. package/src/commands/appDesktopMac.ts +470 -0
  12. package/src/commands/appIcon.ts +187 -0
  13. package/src/commands/appShared.ts +448 -0
  14. package/src/commands/appTemplates.ts +883 -0
  15. package/src/commands/appTemplatesAndroid.ts +599 -0
  16. package/src/commands/appTemplatesGradlew.ts +9 -0
  17. package/src/commands/assets.ts +28 -0
  18. package/src/commands/clone.ts +60 -0
  19. package/src/commands/compile.ts +253 -0
  20. package/src/commands/create.ts +59 -0
  21. package/src/commands/design.ts +863 -0
  22. package/src/commands/designTemplates.ts +11 -0
  23. package/src/commands/desktop.ts +122 -0
  24. package/src/commands/dev.ts +214 -0
  25. package/src/commands/diff.ts +59 -0
  26. package/src/commands/init.ts +191 -0
  27. package/src/commands/install.ts +198 -0
  28. package/src/commands/lightmap.ts +290 -0
  29. package/src/commands/link.ts +147 -0
  30. package/src/commands/login.ts +24 -0
  31. package/src/commands/navmesh.ts +225 -0
  32. package/src/commands/pn.ts +305 -0
  33. package/src/commands/projectTemplates.ts +129 -0
  34. package/src/commands/pull.ts +109 -0
  35. package/src/commands/push.ts +173 -0
  36. package/src/commands/render.ts +414 -0
  37. package/src/commands/scene.ts +148 -0
  38. package/src/commands/shaders.ts +157 -0
  39. package/src/commands/status.ts +29 -0
  40. package/src/commands/test.ts +370 -0
  41. package/src/commands/thumbs.ts +178 -0
  42. package/src/commands/types.ts +87 -0
  43. package/src/commands/update.ts +190 -0
  44. package/src/compile/assetIcons.ts +214 -0
  45. package/src/compile/collect.ts +46 -0
  46. package/src/compile/collectLocal.ts +37 -0
  47. package/src/compile/designCompile.ts +104 -0
  48. package/src/compile/fonts.ts +156 -0
  49. package/src/compile/headlessBundle.ts +129 -0
  50. package/src/compile/nativeStack.ts +21 -0
  51. package/src/compile/projectCompile.ts +109 -0
  52. package/src/compile/sceneCompile.ts +113 -0
  53. package/src/compile/screenEntry.ts +127 -0
  54. package/src/compile/shaders.ts +245 -0
  55. package/src/config.ts +42 -0
  56. package/src/designMeta.ts +35 -0
  57. package/src/desktopRenderer.ts +532 -0
  58. package/src/desktopScript.ts +276 -0
  59. package/src/dev/clientTemplates.ts +160 -0
  60. package/src/dev/devServer.ts +292 -0
  61. package/src/dev/wsServer.ts +144 -0
  62. package/src/distRoot.ts +20 -0
  63. package/src/ignore.ts +163 -0
  64. package/src/index.ts +491 -0
  65. package/src/lecodes-3d-editor.d.ts +41 -0
  66. package/src/lecodes-assets.d.ts +7 -0
  67. package/src/lecodes-design.d.ts +191 -0
  68. package/src/lecodes-renderer.d.ts +131 -0
  69. package/src/localFiles.ts +144 -0
  70. package/src/manifest.ts +46 -0
  71. package/src/matcTool.ts +137 -0
  72. package/src/peers.ts +40 -0
  73. package/src/project.ts +61 -0
  74. package/src/projectEnv.ts +94 -0
  75. package/src/qrcode-terminal.d.ts +9 -0
  76. package/src/releases.ts +125 -0
  77. package/src/serverDiff.ts +78 -0
  78. package/src/textDiff.ts +103 -0
  79. package/src/types.ts +0 -0
  80. package/src/util.ts +146 -0
  81. package/runtime/sdk/animate/animate.ts +0 -238
  82. package/runtime/sdk/animate/bezier.ts +0 -138
  83. package/runtime/sdk/animate/easings.ts +0 -126
  84. package/runtime/sdk/canvas/Canvas.ts +0 -305
  85. package/runtime/sdk/core/Aspect.ts +0 -512
  86. package/runtime/sdk/core/InspectorUI.ts +0 -212
  87. package/runtime/sdk/core/color.ts +0 -66
  88. package/runtime/sdk/core/compWrite.ts +0 -42
  89. package/runtime/sdk/core/events.ts +0 -38
  90. package/runtime/sdk/core/fields.ts +0 -120
  91. package/runtime/sdk/core/registry.ts +0 -23
  92. package/runtime/sdk/core/signals.ts +0 -277
  93. package/runtime/sdk/core/time.ts +0 -81
  94. package/runtime/sdk/g2/Camera2D.ts +0 -40
  95. package/runtime/sdk/g2/CharacterController2D.ts +0 -276
  96. package/runtime/sdk/g2/Node2D.ts +0 -267
  97. package/runtime/sdk/g2/OneWay2D.ts +0 -66
  98. package/runtime/sdk/g2/Physics2D.ts +0 -346
  99. package/runtime/sdk/g2/Scene2D.ts +0 -209
  100. package/runtime/sdk/g2/Shape2D.ts +0 -259
  101. package/runtime/sdk/g2/Sprite.ts +0 -89
  102. package/runtime/sdk/g2/SpriteAnimation.ts +0 -171
  103. package/runtime/sdk/g2/SpriteSheet.ts +0 -166
  104. package/runtime/sdk/g2/Texture2D.ts +0 -47
  105. package/runtime/sdk/g2/Tilemap.ts +0 -41
  106. package/runtime/sdk/g2/Tileset.ts +0 -71
  107. package/runtime/sdk/g2/Trigger2D.ts +0 -77
  108. package/runtime/sdk/g2/autotile.ts +0 -433
  109. package/runtime/sdk/g2/cells.ts +0 -91
  110. package/runtime/sdk/g2/defineScene2d.ts +0 -381
  111. package/runtime/sdk/g2/groups2d.ts +0 -106
  112. package/runtime/sdk/g2/loop.ts +0 -50
  113. package/runtime/sdk/g2/scenarios2d.ts +0 -69
  114. package/runtime/sdk/g2/touch.ts +0 -83
  115. package/runtime/sdk/gl/Camera.ts +0 -160
  116. package/runtime/sdk/gl/CameraPlace.ts +0 -52
  117. package/runtime/sdk/gl/CharacterController.ts +0 -238
  118. package/runtime/sdk/gl/Gearbox.ts +0 -212
  119. package/runtime/sdk/gl/Geometry.ts +0 -279
  120. package/runtime/sdk/gl/IK.ts +0 -193
  121. package/runtime/sdk/gl/InstancedMesh.ts +0 -132
  122. package/runtime/sdk/gl/Light.ts +0 -99
  123. package/runtime/sdk/gl/Lightmap.ts +0 -179
  124. package/runtime/sdk/gl/Material.ts +0 -245
  125. package/runtime/sdk/gl/Mesh.ts +0 -83
  126. package/runtime/sdk/gl/Model.ts +0 -64
  127. package/runtime/sdk/gl/Node.ts +0 -350
  128. package/runtime/sdk/gl/Noise.ts +0 -30
  129. package/runtime/sdk/gl/Particles.ts +0 -676
  130. package/runtime/sdk/gl/Physics.ts +0 -222
  131. package/runtime/sdk/gl/Plane.ts +0 -53
  132. package/runtime/sdk/gl/Ray.ts +0 -16
  133. package/runtime/sdk/gl/Scene.ts +0 -479
  134. package/runtime/sdk/gl/Shape.ts +0 -377
  135. package/runtime/sdk/gl/Texture.ts +0 -46
  136. package/runtime/sdk/gl/Trigger.ts +0 -45
  137. package/runtime/sdk/gl/Vehicle.ts +0 -473
  138. package/runtime/sdk/gl/Wheel.ts +0 -240
  139. package/runtime/sdk/gl/animation/AnimationClip.ts +0 -204
  140. package/runtime/sdk/gl/animation/Animator.ts +0 -87
  141. package/runtime/sdk/gl/animation/Layer.ts +0 -29
  142. package/runtime/sdk/gl/animation/Loop.ts +0 -25
  143. package/runtime/sdk/gl/animation/Playback.ts +0 -43
  144. package/runtime/sdk/gl/animation/core.ts +0 -294
  145. package/runtime/sdk/gl/controls.ts +0 -95
  146. package/runtime/sdk/gl/physicsEvents.ts +0 -20
  147. package/runtime/sdk/gl/scenarios.ts +0 -291
  148. package/runtime/sdk/gl/state.ts +0 -6
  149. package/runtime/sdk/gl/touch.ts +0 -68
  150. package/runtime/sdk/inject.ts +0 -186
  151. package/runtime/sdk/math/Mathf.ts +0 -118
  152. package/runtime/sdk/math/mat4.ts +0 -278
  153. package/runtime/sdk/math/quat.ts +0 -232
  154. package/runtime/sdk/math/vec.ts +0 -255
  155. package/runtime/sdk/plugins/camera.ts +0 -81
  156. package/runtime/sdk/plugins/geolocation.ts +0 -123
  157. package/runtime/sdk/plugins/oauth.ts +0 -61
  158. package/runtime/sdk/plugins/permission.ts +0 -7
  159. package/runtime/sdk/plugins/push.ts +0 -132
  160. package/runtime/sdk/plugins/qr.ts +0 -73
  161. package/runtime/sdk/plugins/service.ts +0 -47
  162. package/runtime/sdk/runtime/app.ts +0 -101
  163. package/runtime/sdk/runtime/appEvents.ts +0 -54
  164. package/runtime/sdk/runtime/channel.ts +0 -61
  165. package/runtime/sdk/runtime/clipboard.ts +0 -20
  166. package/runtime/sdk/runtime/datetime.ts +0 -329
  167. package/runtime/sdk/runtime/device.ts +0 -293
  168. package/runtime/sdk/runtime/fetch.ts +0 -77
  169. package/runtime/sdk/runtime/files.ts +0 -23
  170. package/runtime/sdk/runtime/input.ts +0 -175
  171. package/runtime/sdk/runtime/media.ts +0 -111
  172. package/runtime/sdk/runtime/misc.ts +0 -16
  173. package/runtime/sdk/runtime/net.ts +0 -36
  174. package/runtime/sdk/runtime/rpc.ts +0 -218
  175. package/runtime/sdk/runtime/service.ts +0 -83
  176. package/runtime/sdk/runtime/share.ts +0 -9
  177. package/runtime/sdk/runtime/storage.ts +0 -13
  178. package/runtime/sdk/runtime/touch.ts +0 -76
  179. package/runtime/sdk/scene/defineScene.ts +0 -1227
  180. package/runtime/sdk/scene/editorPlugins.ts +0 -92
  181. package/runtime/sdk/scene/gizmos.ts +0 -148
  182. package/runtime/sdk/scene/grammar.ts +0 -120
  183. package/runtime/sdk/scene/material.ts +0 -188
  184. package/runtime/sdk/server/auth/appConfig.ts +0 -12
  185. package/runtime/sdk/server/auth/global.ts +0 -80
  186. package/runtime/sdk/server/auth/host.ts +0 -318
  187. package/runtime/sdk/server/auth/models.ts +0 -83
  188. package/runtime/sdk/server/auth/types.ts +0 -50
  189. package/runtime/sdk/server/channel.ts +0 -56
  190. package/runtime/sdk/server/context.ts +0 -36
  191. package/runtime/sdk/server/db/defineDb.ts +0 -237
  192. package/runtime/sdk/server/db/fields.ts +0 -132
  193. package/runtime/sdk/server/db/httpTransport.ts +0 -93
  194. package/runtime/sdk/server/db/index.ts +0 -7
  195. package/runtime/sdk/server/db/marci/query.ts +0 -412
  196. package/runtime/sdk/server/db/types.ts +0 -202
  197. package/runtime/sdk/server/errors.ts +0 -12
  198. package/runtime/sdk/server/host.ts +0 -74
  199. package/runtime/sdk/server/inject.ts +0 -13
  200. package/runtime/sdk/server/runtime.ts +0 -133
  201. package/runtime/sdk/server/validate.ts +0 -87
  202. package/runtime/sdk/ui/NativeView.ts +0 -142
  203. package/runtime/sdk/ui/UI.ts +0 -39
  204. package/runtime/sdk/ui/UIBottomSheet.ts +0 -139
  205. package/runtime/sdk/ui/UIButton.ts +0 -101
  206. package/runtime/sdk/ui/UIContainer.ts +0 -60
  207. package/runtime/sdk/ui/UIImage.ts +0 -83
  208. package/runtime/sdk/ui/UIInput.ts +0 -185
  209. package/runtime/sdk/ui/UIModal.ts +0 -139
  210. package/runtime/sdk/ui/UINode.ts +0 -826
  211. package/runtime/sdk/ui/UIPager.ts +0 -362
  212. package/runtime/sdk/ui/UIPopover.ts +0 -100
  213. package/runtime/sdk/ui/UIScreen.ts +0 -123
  214. package/runtime/sdk/ui/UIScrollable.ts +0 -87
  215. package/runtime/sdk/ui/UISpacer.ts +0 -14
  216. package/runtime/sdk/ui/UITabs.ts +0 -236
  217. package/runtime/sdk/ui/UIText.ts +0 -51
  218. package/runtime/sdk/ui/UIVideo.ts +0 -88
  219. package/runtime/sdk/ui/UIVirtualizedList.ts +0 -241
  220. package/runtime/sdk/ui/UIWidget.ts +0 -127
  221. package/runtime/sdk/ui/fonts.ts +0 -13
  222. package/runtime/sdk/ui/presentable.ts +0 -117
  223. package/runtime/sdk/ui/router.ts +0 -132
  224. package/runtime/sdk/ui/theme.ts +0 -84
@@ -1,278 +0,0 @@
1
- // Fluent 4×4 matrix (column-major) — the SDK's transform/projection type. Same contract as Vec/Quat:
2
- // the methods are PURE (each returns a new Mat4), but — per the "never wrap away the metal" rule — the
3
- // raw backing array is PUBLIC as `.m` (length 16). So low-level numeric surgery (`mat.m[12] += vx*dt`)
4
- // drops straight to the array with zero ceremony, while the fluent methods express the high-level logic.
5
- //
6
- // Backing is a plain `number[]` (not a Float32Array) so a future optimizer can see through it; the
7
- // Float32Array the host bridge wants is produced only at the edge via `toFloat32Array()`.
8
- //
9
- // This folds in the old `math/transform.ts` decomposition (position / scale / rotation / euler).
10
-
11
- import { Vec3, type Vec3Like } from "./vec"
12
- import { Quat, quatFromColMajor, eulerFromColMajor, type QuatLike, type EulerOrder } from "./quat"
13
-
14
- export type Mat4Like = Mat4 | number[] | Float32Array | readonly number[]
15
-
16
- const arr = (m: Mat4Like): ArrayLike<number> => (m as { m?: ArrayLike<number> }).m ?? (m as ArrayLike<number>)
17
- const IDENTITY = [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]
18
-
19
- export class Mat4 {
20
- /** The raw column-major elements (length 16). Public on purpose — read/write directly when you want
21
- * the metal: `mat.m[12] += vx * dt`. The fluent methods never mutate it (they return a new Mat4). */
22
- m: number[]
23
-
24
- constructor(src?: Mat4Like) {
25
- if (src === undefined) { this.m = IDENTITY.slice(); return }
26
- const s = arr(src)
27
- this.m = [ s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15] ]
28
- }
29
-
30
- // --- mutation ---
31
- set(values: ArrayLike<number>): this { for (let i = 0; i < 16; i++) this.m[i] = values[i]; return this }
32
- copy(src: Mat4Like): this { return this.set(arr(src)) }
33
-
34
- // --- products (pure) ---
35
- /** `this · b` (apply `b` first in local space, then `this`). */
36
- mul(b: Mat4Like): Mat4 {
37
- const a = this.m, o = arr(b), out = new Array(16)
38
- const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]
39
- const a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]
40
- const a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]
41
- const a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]
42
- for (let i = 0; i < 4; i++) {
43
- const b0 = o[i * 4], b1 = o[i * 4 + 1], b2 = o[i * 4 + 2], b3 = o[i * 4 + 3]
44
- out[i * 4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30
45
- out[i * 4 + 1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31
46
- out[i * 4 + 2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32
47
- out[i * 4 + 3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33
48
- }
49
- return fromArray(out)
50
- }
51
- /** `b · this` — multiply on the other side (apply `this` first, then `b`). */
52
- premul(b: Mat4Like): Mat4 { return new Mat4(b).mul(this) }
53
-
54
- invert(): Mat4 {
55
- const a = this.m
56
- const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]
57
- const a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]
58
- const a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]
59
- const a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]
60
- const b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10, b02 = a00 * a13 - a03 * a10
61
- const b03 = a01 * a12 - a02 * a11, b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12
62
- const b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30, b08 = a20 * a33 - a23 * a30
63
- const b09 = a21 * a32 - a22 * a31, b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32
64
- let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06
65
- if (!det) return new Mat4() // singular → identity
66
- det = 1 / det
67
- return fromArray([
68
- (a11 * b11 - a12 * b10 + a13 * b09) * det, (a02 * b10 - a01 * b11 - a03 * b09) * det,
69
- (a31 * b05 - a32 * b04 + a33 * b03) * det, (a22 * b04 - a21 * b05 - a23 * b03) * det,
70
- (a12 * b08 - a10 * b11 - a13 * b07) * det, (a00 * b11 - a02 * b08 + a03 * b07) * det,
71
- (a32 * b02 - a30 * b05 - a33 * b01) * det, (a20 * b05 - a22 * b02 + a23 * b01) * det,
72
- (a10 * b10 - a11 * b08 + a13 * b06) * det, (a01 * b08 - a00 * b10 - a03 * b06) * det,
73
- (a30 * b04 - a31 * b02 + a33 * b00) * det, (a21 * b02 - a20 * b04 - a23 * b00) * det,
74
- (a11 * b07 - a10 * b09 - a12 * b06) * det, (a00 * b09 - a01 * b07 + a02 * b06) * det,
75
- (a31 * b01 - a30 * b03 - a32 * b00) * det, (a20 * b03 - a21 * b01 + a22 * b00) * det,
76
- ])
77
- }
78
- transpose(): Mat4 {
79
- const a = this.m
80
- return fromArray([ a[0], a[4], a[8], a[12], a[1], a[5], a[9], a[13], a[2], a[6], a[10], a[14], a[3], a[7], a[11], a[15] ])
81
- }
82
- determinant(): number {
83
- const a = this.m
84
- const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]
85
- const a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]
86
- const a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]
87
- const a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]
88
- const b0 = a00 * a11 - a01 * a10, b1 = a00 * a12 - a02 * a10, b2 = a01 * a12 - a02 * a11
89
- const b3 = a20 * a31 - a21 * a30, b4 = a20 * a32 - a22 * a30, b5 = a21 * a32 - a22 * a31
90
- const b6 = a00 * b5 - a01 * b4 + a02 * b3, b7 = a10 * b5 - a11 * b4 + a12 * b3
91
- const b8 = a20 * b2 - a21 * b1 + a22 * b0, b9 = a30 * b2 - a31 * b1 + a32 * b0
92
- return a13 * b6 - a03 * b7 + a33 * b8 - a23 * b9
93
- }
94
-
95
- // --- local-space transforms (post-multiply: this · T) ---
96
- /** `this · translate(v)`. */
97
- translate(v: Vec3Like): Mat4 {
98
- const a = this.m, x = ax(v), y = ay(v), z = az(v), out = a.slice()
99
- out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]
100
- out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]
101
- out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]
102
- out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]
103
- return fromArray(out)
104
- }
105
- /** `this · scale(v)`. Accepts a vector or a uniform scalar. */
106
- scale(v: Vec3Like | number): Mat4 {
107
- const a = this.m
108
- const x = typeof v === "number" ? v : ax(v), y = typeof v === "number" ? v : ay(v), z = typeof v === "number" ? v : az(v)
109
- return fromArray([
110
- a[0] * x, a[1] * x, a[2] * x, a[3] * x, a[4] * y, a[5] * y, a[6] * y, a[7] * y,
111
- a[8] * z, a[9] * z, a[10] * z, a[11] * z, a[12], a[13], a[14], a[15],
112
- ])
113
- }
114
- /** `this · rotate(axis, rad)`. */
115
- rotate(rad: number, axis: Vec3Like): Mat4 {
116
- let x = ax(axis), y = ay(axis), z = az(axis)
117
- let len = Math.hypot(x, y, z)
118
- if (len < 1e-6) return this.clone()
119
- len = 1 / len; x *= len; y *= len; z *= len
120
- const s = Math.sin(rad), c = Math.cos(rad), t = 1 - c
121
- const a = this.m
122
- const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]
123
- const a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]
124
- const a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]
125
- const b00 = x * x * t + c, b01 = y * x * t + z * s, b02 = z * x * t - y * s
126
- const b10 = x * y * t - z * s, b11 = y * y * t + c, b12 = z * y * t + x * s
127
- const b20 = x * z * t + y * s, b21 = y * z * t - x * s, b22 = z * z * t + c
128
- return fromArray([
129
- a00 * b00 + a10 * b01 + a20 * b02, a01 * b00 + a11 * b01 + a21 * b02, a02 * b00 + a12 * b01 + a22 * b02, a03 * b00 + a13 * b01 + a23 * b02,
130
- a00 * b10 + a10 * b11 + a20 * b12, a01 * b10 + a11 * b11 + a21 * b12, a02 * b10 + a12 * b11 + a22 * b12, a03 * b10 + a13 * b11 + a23 * b12,
131
- a00 * b20 + a10 * b21 + a20 * b22, a01 * b20 + a11 * b21 + a21 * b22, a02 * b20 + a12 * b21 + a22 * b22, a03 * b20 + a13 * b21 + a23 * b22,
132
- a[12], a[13], a[14], a[15],
133
- ])
134
- }
135
- rotateX(rad: number): Mat4 { return this.rotate(rad, AXIS_X) }
136
- rotateY(rad: number): Mat4 { return this.rotate(rad, AXIS_Y) }
137
- rotateZ(rad: number): Mat4 { return this.rotate(rad, AXIS_Z) }
138
-
139
- // --- vector transforms ---
140
- /** Transform a point (applies translation + perspective divide). */
141
- transformPoint(v: Vec3Like): Vec3 { return new Vec3(v).transform(this) }
142
- /** Transform a direction (rotation/scale only — no translation, no divide). */
143
- transformDirection(v: Vec3Like): Vec3 {
144
- const a = this.m, x = ax(v), y = ay(v), z = az(v)
145
- return new Vec3(a[0] * x + a[4] * y + a[8] * z, a[1] * x + a[5] * y + a[9] * z, a[2] * x + a[6] * y + a[10] * z)
146
- }
147
-
148
- // --- decomposition (folded from transform.ts) ---
149
- get position(): Vec3 { const a = this.m; return new Vec3(a[12], a[13], a[14]) }
150
- get scaling(): Vec3 {
151
- const a = this.m
152
- return new Vec3(Math.hypot(a[0], a[1], a[2]), Math.hypot(a[4], a[5], a[6]), Math.hypot(a[8], a[9], a[10]))
153
- }
154
- get rotation(): Quat { return quatFromColMajor(rotationOnly(this.m)) }
155
- get eulerAngles(): Vec3 { return eulerFromColMajor(rotationOnly(this.m), "YXZ") }
156
- toEuler(order: EulerOrder = "YXZ"): Vec3 { return eulerFromColMajor(rotationOnly(this.m), order) }
157
- /** `{ position, rotation, scale }` in one shot. */
158
- decompose(): { position: Vec3, rotation: Quat, scale: Vec3 } {
159
- return { position: this.position, rotation: this.rotation, scale: this.scaling }
160
- }
161
-
162
- /** Column basis vectors (the local X / Y / Z axes in world space). */
163
- get basisX(): Vec3 { const a = this.m; return new Vec3(a[0], a[1], a[2]) }
164
- get basisY(): Vec3 { const a = this.m; return new Vec3(a[4], a[5], a[6]) }
165
- get basisZ(): Vec3 { const a = this.m; return new Vec3(a[8], a[9], a[10]) }
166
-
167
- // --- interop ---
168
- clone(): Mat4 { return new Mat4(this) }
169
- toArray(): number[] { return this.m.slice() }
170
- toFloat32Array(): Float32Array { return Float32Array.from(this.m) }
171
- equals(b: Mat4Like, eps = 1e-6): boolean {
172
- const o = arr(b)
173
- for (let i = 0; i < 16; i++) {
174
- if (Math.abs(this.m[i] - o[i]) > eps * Math.max(1, Math.abs(this.m[i]), Math.abs(o[i]))) return false
175
- }
176
- return true
177
- }
178
-
179
- // --- factories ---
180
- static identity(): Mat4 { return new Mat4() }
181
- static from(src: Mat4Like): Mat4 { return new Mat4(src) }
182
-
183
- /** Translation · Rotation · Scale into one matrix. `scale` defaults to 1 and accepts a scalar. */
184
- static compose(position: Vec3Like, rotation: QuatLike, scale: Vec3Like | number = 1): Mat4 {
185
- const x = qx(rotation), y = qy(rotation), z = qz(rotation), w = qw(rotation)
186
- const x2 = x + x, y2 = y + y, z2 = z + z
187
- const xx = x * x2, xy = x * y2, xz = x * z2
188
- const yy = y * y2, yz = y * z2, zz = z * z2
189
- const wx = w * x2, wy = w * y2, wz = w * z2
190
- const sx = typeof scale === "number" ? scale : ax(scale)
191
- const sy = typeof scale === "number" ? scale : ay(scale)
192
- const sz = typeof scale === "number" ? scale : az(scale)
193
- return fromArray([
194
- (1 - (yy + zz)) * sx, (xy + wz) * sx, (xz - wy) * sx, 0,
195
- (xy - wz) * sy, (1 - (xx + zz)) * sy, (yz + wx) * sy, 0,
196
- (xz + wy) * sz, (yz - wx) * sz, (1 - (xx + yy)) * sz, 0,
197
- ax(position), ay(position), az(position), 1,
198
- ])
199
- }
200
- static fromQuat(q: QuatLike): Mat4 { return Mat4.compose(ORIGIN, q, 1) }
201
- static fromTranslation(v: Vec3Like): Mat4 { const m = new Mat4(); m.m[12] = ax(v); m.m[13] = ay(v); m.m[14] = az(v); return m }
202
- static fromScale(v: Vec3Like | number): Mat4 { return new Mat4().scale(v) }
203
- static fromEuler(x: number, y: number, z: number, order: EulerOrder = "YXZ"): Mat4 {
204
- return Mat4.fromQuat(Quat.fromEuler(x, y, z, order))
205
- }
206
-
207
- /** A view matrix that looks from `eye` toward `center` with `up`. */
208
- static lookAt(eye: Vec3Like, center: Vec3Like, up: Vec3Like = Vec3.up): Mat4 {
209
- const ex = ax(eye), ey = ay(eye), ez = az(eye)
210
- let z0 = ex - ax(center), z1 = ey - ay(center), z2 = ez - az(center)
211
- let len = Math.hypot(z0, z1, z2)
212
- if (len < 1e-6) return new Mat4()
213
- len = 1 / len; z0 *= len; z1 *= len; z2 *= len
214
- const ux = ax(up), uy = ay(up), uz = az(up)
215
- let x0 = uy * z2 - uz * z1, x1 = uz * z0 - ux * z2, x2 = ux * z1 - uy * z0
216
- len = Math.hypot(x0, x1, x2)
217
- if (len) { len = 1 / len; x0 *= len; x1 *= len; x2 *= len } else { x0 = x1 = x2 = 0 }
218
- const y0 = z1 * x2 - z2 * x1, y1 = z2 * x0 - z0 * x2, y2 = z0 * x1 - z1 * x0
219
- return fromArray([
220
- x0, y0, z0, 0, x1, y1, z1, 0, x2, y2, z2, 0,
221
- -(x0 * ex + x1 * ey + x2 * ez), -(y0 * ex + y1 * ey + y2 * ez), -(z0 * ex + z1 * ey + z2 * ez), 1,
222
- ])
223
- }
224
- /** A world matrix that places something at `eye` oriented to look at `target`. */
225
- static targetTo(eye: Vec3Like, target: Vec3Like, up: Vec3Like = Vec3.up): Mat4 {
226
- const ex = ax(eye), ey = ay(eye), ez = az(eye)
227
- let z0 = ex - ax(target), z1 = ey - ay(target), z2 = ez - az(target)
228
- let len = z0 * z0 + z1 * z1 + z2 * z2
229
- if (len > 0) { len = 1 / Math.sqrt(len); z0 *= len; z1 *= len; z2 *= len }
230
- const ux = ax(up), uy = ay(up), uz = az(up)
231
- let x0 = uy * z2 - uz * z1, x1 = uz * z0 - ux * z2, x2 = ux * z1 - uy * z0
232
- len = x0 * x0 + x1 * x1 + x2 * x2
233
- if (len > 0) { len = 1 / Math.sqrt(len); x0 *= len; x1 *= len; x2 *= len }
234
- return fromArray([
235
- x0, x1, x2, 0, z1 * x2 - z2 * x1, z2 * x0 - z0 * x2, z0 * x1 - z1 * x0, 0,
236
- z0, z1, z2, 0, ex, ey, ez, 1,
237
- ])
238
- }
239
- /** Perspective projection (WebGL/OpenGL clip, NDC z ∈ [−1, 1]). `fovy` is in RADIANS. */
240
- static perspective(fovy: number, aspect: number, near: number, far: number): Mat4 {
241
- const f = 1 / Math.tan(fovy / 2), out = new Array(16).fill(0)
242
- out[0] = f / aspect; out[5] = f; out[11] = -1
243
- if (far !== Infinity) { const nf = 1 / (near - far); out[10] = (far + near) * nf; out[14] = 2 * far * near * nf }
244
- else { out[10] = -1; out[14] = -2 * near }
245
- return fromArray(out)
246
- }
247
- /** Orthographic projection (WebGL/OpenGL clip, NDC z ∈ [−1, 1]). */
248
- static ortho(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4 {
249
- const lr = 1 / (left - right), bt = 1 / (bottom - top), nf = 1 / (near - far)
250
- return fromArray([
251
- -2 * lr, 0, 0, 0, 0, -2 * bt, 0, 0, 0, 0, 2 * nf, 0,
252
- (left + right) * lr, (top + bottom) * bt, (far + near) * nf, 1,
253
- ])
254
- }
255
- }
256
-
257
- // fast path: wrap an already-built length-16 array as a Mat4 without re-copying it.
258
- const fromArray = (m: number[]): Mat4 => { const r = Object.create(Mat4.prototype) as Mat4; r.m = m; return r }
259
-
260
- /** The 3×3 rotation part with scale divided out, as a column-major length-≥11 array (for quat/euler). */
261
- const rotationOnly = (a: ArrayLike<number>): number[] => {
262
- const sx = Math.hypot(a[0], a[1], a[2]) || 1, sy = Math.hypot(a[4], a[5], a[6]) || 1, sz = Math.hypot(a[8], a[9], a[10]) || 1
263
- const i1 = 1 / sx, i2 = 1 / sy, i3 = 1 / sz
264
- return [ a[0] * i1, a[1] * i1, a[2] * i1, 0, a[4] * i2, a[5] * i2, a[6] * i2, 0, a[8] * i3, a[9] * i3, a[10] * i3 ]
265
- }
266
-
267
- const ax = (v: Vec3Like): number => (v as { x?: number }).x ?? (v as ArrayLike<number>)[0]
268
- const ay = (v: Vec3Like): number => (v as { y?: number }).y ?? (v as ArrayLike<number>)[1]
269
- const az = (v: Vec3Like): number => (v as { z?: number }).z ?? (v as ArrayLike<number>)[2]
270
- const qx = (q: QuatLike): number => (q as { x?: number }).x ?? (q as ArrayLike<number>)[0]
271
- const qy = (q: QuatLike): number => (q as { y?: number }).y ?? (q as ArrayLike<number>)[1]
272
- const qz = (q: QuatLike): number => (q as { z?: number }).z ?? (q as ArrayLike<number>)[2]
273
- const qw = (q: QuatLike): number => (q as { w?: number }).w ?? (q as ArrayLike<number>)[3]
274
-
275
- const AXIS_X: Vec3Like = [ 1, 0, 0 ]
276
- const AXIS_Y: Vec3Like = [ 0, 1, 0 ]
277
- const AXIS_Z: Vec3Like = [ 0, 0, 1 ]
278
- const ORIGIN: Vec3Like = [ 0, 0, 0 ]
@@ -1,232 +0,0 @@
1
- // Fluent quaternion (x, y, z, w) — the rotation type for the 3D node API. Same contract as Vec: mutable
2
- // fields, PURE methods (each returns a new Quat). Accepts a `Quat` or a raw `[x, y, z, w]` everywhere.
3
- //
4
- // Convention: standard right-handed, column-major (matches gl-matrix and three.js). Euler angles are in
5
- // DEGREES. The euler order default is "YXZ" (yaw-pitch-roll, the usual choice for cameras / characters).
6
- //
7
- // NB: this fixes a transpose bug in the old `transform.ts` euler extraction, which read the matrix with
8
- // row/col swapped and so returned a NEGATED angle for a positive rotation. `eulerFromColMajor` below uses
9
- // the correct column-major element mapping, so `node.eulerAngles` now round-trips with the setter.
10
-
11
- import { Vec3, cx, cy, cz, type Vec3Like } from "./vec"
12
-
13
- export type QuatLike = Quat | readonly [number, number, number, number] | number[] | Float32Array
14
- export type EulerOrder = "XYZ" | "YXZ" | "ZXY" | "ZYX" | "YZX" | "XZY"
15
-
16
- /** Read the w / 4th component of any quaternion-like (wrapper `.w`, or array-like `[3]`). */
17
- export const cw = (q: { w?: number } | ArrayLike<number>): number => (q as { w?: number }).w ?? (q as ArrayLike<number>)[3]
18
- const DEG2RAD = Math.PI / 180
19
- const RAD2DEG = 180 / Math.PI
20
- const EPS = 1e-6
21
- const approx = (a: number, b: number, eps: number): boolean => Math.abs(a - b) <= eps * Math.max(1, Math.abs(a), Math.abs(b))
22
- const clamp1 = (v: number): number => (v < -1 ? -1 : v > 1 ? 1 : v)
23
-
24
- export class Quat {
25
- x: number
26
- y: number
27
- z: number
28
- w: number
29
-
30
- constructor(x: number | QuatLike = 0, y = 0, z = 0, w = 1) {
31
- if (typeof x === "number") { this.x = x; this.y = y; this.z = z; this.w = w }
32
- else { this.x = cx(x); this.y = cy(x); this.z = cz(x); this.w = cw(x) }
33
- }
34
-
35
- // --- mutation ---
36
- set(x: number, y: number, z: number, w: number): this { this.x = x; this.y = y; this.z = z; this.w = w; return this }
37
- copy(q: QuatLike): this { this.x = cx(q); this.y = cy(q); this.z = cz(q); this.w = cw(q); return this }
38
-
39
- // --- pure ops ---
40
- /** Hamilton product `this ⊗ b` (apply `b` first, then `this`). */
41
- mul(b: QuatLike): Quat {
42
- const ax = this.x, ay = this.y, az = this.z, aw = this.w
43
- const bx = cx(b), by = cy(b), bz = cz(b), bw = cw(b)
44
- return new Quat(
45
- ax * bw + aw * bx + ay * bz - az * by,
46
- ay * bw + aw * by + az * bx - ax * bz,
47
- az * bw + aw * bz + ax * by - ay * bx,
48
- aw * bw - ax * bx - ay * by - az * bz,
49
- )
50
- }
51
- normalize(): Quat {
52
- let l = Math.hypot(this.x, this.y, this.z, this.w)
53
- if (l === 0) return new Quat(0, 0, 0, 1)
54
- l = 1 / l
55
- return new Quat(this.x * l, this.y * l, this.z * l, this.w * l)
56
- }
57
- conjugate(): Quat { return new Quat(-this.x, -this.y, -this.z, this.w) }
58
- /** Inverse rotation. For a unit quaternion this equals `conjugate()`. */
59
- invert(): Quat {
60
- const d = this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w
61
- if (d === 0) return new Quat(0, 0, 0, 0)
62
- const i = 1 / d
63
- return new Quat(-this.x * i, -this.y * i, -this.z * i, this.w * i)
64
- }
65
- dot(b: QuatLike): number { return this.x * cx(b) + this.y * cy(b) + this.z * cz(b) + this.w * cw(b) }
66
- /** Spherical interpolation toward `b` by `t ∈ [0, 1]`. */
67
- slerp(b: QuatLike, t: number): Quat {
68
- const ax = this.x, ay = this.y, az = this.z, aw = this.w
69
- let bx = cx(b), by = cy(b), bz = cz(b), bw = cw(b)
70
- let cosom = ax * bx + ay * by + az * bz + aw * bw
71
- if (cosom < 0) { cosom = -cosom; bx = -bx; by = -by; bz = -bz; bw = -bw }
72
- let s0: number, s1: number
73
- if (1 - cosom > EPS) {
74
- const omega = Math.acos(cosom), sinom = Math.sin(omega)
75
- s0 = Math.sin((1 - t) * omega) / sinom
76
- s1 = Math.sin(t * omega) / sinom
77
- } else { s0 = 1 - t; s1 = t }
78
- return new Quat(s0 * ax + s1 * bx, s0 * ay + s1 * by, s0 * az + s1 * bz, s0 * aw + s1 * bw)
79
- }
80
- /** Angular distance (radians) between two unit quaternions. */
81
- angle(b: QuatLike): number {
82
- const d = this.dot(b)
83
- return Math.acos(clamp1(2 * d * d - 1))
84
- }
85
- /** Rotate a vector by this quaternion → a new `Vec3`. */
86
- rotateVec3(v: Vec3Like): Vec3 { return new Vec3(v).rotate(this) }
87
-
88
- /** Extract euler angles (DEGREES) in the given order. */
89
- toEuler(order: EulerOrder = "YXZ"): Vec3 {
90
- // build the (column-major) rotation matrix entries from the unit quaternion, then extract.
91
- const x = this.x, y = this.y, z = this.z, w = this.w
92
- const x2 = x + x, y2 = y + y, z2 = z + z
93
- const xx = x * x2, xy = x * y2, xz = x * z2
94
- const yy = y * y2, yz = y * z2, zz = z * z2
95
- const wx = w * x2, wy = w * y2, wz = w * z2
96
- const m = [
97
- 1 - (yy + zz), xy + wz, xz - wy, 0,
98
- xy - wz, 1 - (xx + zz), yz + wx, 0,
99
- xz + wy, yz - wx, 1 - (xx + yy), 0,
100
- ]
101
- return eulerFromColMajor(m, order)
102
- }
103
-
104
- // --- interop ---
105
- equals(b: QuatLike, eps = 1e-6): boolean {
106
- return approx(this.x, cx(b), eps) && approx(this.y, cy(b), eps) && approx(this.z, cz(b), eps) && approx(this.w, cw(b), eps)
107
- }
108
- /** True if the two unit quaternions represent the same rotation (±q are equal). */
109
- sameRotation(b: QuatLike, eps = 1e-6): boolean { return Math.abs(this.dot(b)) >= 1 - eps }
110
- clone(): Quat { return new Quat(this.x, this.y, this.z, this.w) }
111
- toArray(): [number, number, number, number] { return [ this.x, this.y, this.z, this.w ] }
112
- *[Symbol.iterator](): Iterator<number> { yield this.x; yield this.y; yield this.z; yield this.w }
113
-
114
- // --- factories ---
115
- static from(q: QuatLike): Quat { return new Quat(cx(q), cy(q), cz(q), cw(q)) }
116
- static get identity(): Quat { return new Quat(0, 0, 0, 1) }
117
-
118
- /** From euler angles in DEGREES (default order "YXZ"). Inverts `toEuler`. */
119
- static fromEuler(x: number, y: number, z: number, order: EulerOrder = "YXZ"): Quat {
120
- const c1 = Math.cos(x * DEG2RAD / 2), c2 = Math.cos(y * DEG2RAD / 2), c3 = Math.cos(z * DEG2RAD / 2)
121
- const s1 = Math.sin(x * DEG2RAD / 2), s2 = Math.sin(y * DEG2RAD / 2), s3 = Math.sin(z * DEG2RAD / 2)
122
- switch (order) {
123
- case "XYZ": return new Quat(s1 * c2 * c3 + c1 * s2 * s3, c1 * s2 * c3 - s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3)
124
- case "YXZ": return new Quat(s1 * c2 * c3 + c1 * s2 * s3, c1 * s2 * c3 - s1 * c2 * s3, c1 * c2 * s3 - s1 * s2 * c3, c1 * c2 * c3 + s1 * s2 * s3)
125
- case "ZXY": return new Quat(s1 * c2 * c3 - c1 * s2 * s3, c1 * s2 * c3 + s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3)
126
- case "ZYX": return new Quat(s1 * c2 * c3 - c1 * s2 * s3, c1 * s2 * c3 + s1 * c2 * s3, c1 * c2 * s3 - s1 * s2 * c3, c1 * c2 * c3 + s1 * s2 * s3)
127
- case "YZX": return new Quat(s1 * c2 * c3 + c1 * s2 * s3, c1 * s2 * c3 + s1 * c2 * s3, c1 * c2 * s3 - s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3)
128
- case "XZY": return new Quat(s1 * c2 * c3 - c1 * s2 * s3, c1 * s2 * c3 - s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 + s1 * s2 * s3)
129
- }
130
- }
131
-
132
- /** From a rotation `axis` and an angle in RADIANS. The axis is normalized for you. */
133
- static fromAxisAngle(axis: Vec3Like, rad: number): Quat {
134
- let ax = cx(axis), ay = cy(axis), az = cz(axis)
135
- const l = Math.hypot(ax, ay, az)
136
- if (l === 0) return new Quat(0, 0, 0, 1)
137
- ax /= l; ay /= l; az /= l
138
- const s = Math.sin(rad / 2)
139
- return new Quat(ax * s, ay * s, az * s, Math.cos(rad / 2))
140
- }
141
-
142
- /** The shortest rotation that takes direction `a` onto direction `b`. */
143
- static fromTo(a: Vec3Like, b: Vec3Like): Quat {
144
- const A = new Vec3(a).normalize(), B = new Vec3(b).normalize()
145
- const d = A.dot(B)
146
- if (d > 0.999999) return new Quat(0, 0, 0, 1)
147
- if (d < -0.999999) {
148
- // antiparallel: rotate 180° about any axis ⟂ A.
149
- let axis = new Vec3(1, 0, 0).cross(A)
150
- if (axis.lengthSq() < 1e-12) axis = new Vec3(0, 1, 0).cross(A)
151
- return Quat.fromAxisAngle(axis.normalize(), Math.PI)
152
- }
153
- const c = A.cross(B)
154
- return new Quat(c.x, c.y, c.z, 1 + d).normalize()
155
- }
156
-
157
- /** A rotation whose forward (−Z) points along `forward`, with `up` as the reference up axis. */
158
- static lookRotation(forward: Vec3Like, up: Vec3Like = Vec3.up): Quat {
159
- const zc = new Vec3(forward).normalize().negate() // local +Z basis (forward is −Z)
160
- let xc = new Vec3(up).cross(zc)
161
- if (xc.lengthSq() < 1e-12) xc = new Vec3(up).cross(zc.add([ 1e-4, 0, 0 ]))
162
- xc = xc.normalize()
163
- const yc = zc.cross(xc)
164
- return quatFromColMajor([ xc.x, xc.y, xc.z, 0, yc.x, yc.y, yc.z, 0, zc.x, zc.y, zc.z ])
165
- }
166
- }
167
-
168
- /** Quaternion from a column-major rotation matrix (≥3×3, indices 0,1,2,4,5,6,8,9,10). gl-matrix's
169
- * `getRotation` algorithm — the exact inverse of building a matrix from a quaternion. */
170
- export const quatFromColMajor = (m: ArrayLike<number>): Quat => {
171
- const m00 = m[0], m01 = m[1], m02 = m[2]
172
- const m10 = m[4], m11 = m[5], m12 = m[6]
173
- const m20 = m[8], m21 = m[9], m22 = m[10]
174
- const trace = m00 + m11 + m22
175
- let S: number
176
- if (trace > 0) {
177
- S = Math.sqrt(trace + 1) * 2
178
- return new Quat((m12 - m21) / S, (m20 - m02) / S, (m01 - m10) / S, 0.25 * S)
179
- } else if (m00 > m11 && m00 > m22) {
180
- S = Math.sqrt(1 + m00 - m11 - m22) * 2
181
- return new Quat(0.25 * S, (m01 + m10) / S, (m20 + m02) / S, (m12 - m21) / S)
182
- } else if (m11 > m22) {
183
- S = Math.sqrt(1 + m11 - m00 - m22) * 2
184
- return new Quat((m01 + m10) / S, 0.25 * S, (m12 + m21) / S, (m20 - m02) / S)
185
- } else {
186
- S = Math.sqrt(1 + m22 - m00 - m11) * 2
187
- return new Quat((m20 + m02) / S, (m12 + m21) / S, 0.25 * S, (m01 - m10) / S)
188
- }
189
- }
190
-
191
- /** Euler angles (DEGREES) from a column-major rotation matrix, standard three.js extraction.
192
- * Element naming follows the column-major layout: mRC = m[(C-1)*4 + (R-1)]. */
193
- export const eulerFromColMajor = (m: ArrayLike<number>, order: EulerOrder = "YXZ"): Vec3 => {
194
- const m11 = m[0], m21 = m[1], m31 = m[2]
195
- const m12 = m[4], m22 = m[5], m32 = m[6]
196
- const m13 = m[8], m23 = m[9], m33 = m[10]
197
- let x = 0, y = 0, z = 0
198
- const LIM = 0.9999999
199
- switch (order) {
200
- case "XYZ":
201
- y = Math.asin(clamp1(m13))
202
- if (Math.abs(m13) < LIM) { x = Math.atan2(-m23, m33); z = Math.atan2(-m12, m11) }
203
- else { x = Math.atan2(m32, m22); z = 0 }
204
- break
205
- case "YXZ":
206
- x = Math.asin(-clamp1(m23))
207
- if (Math.abs(m23) < LIM) { y = Math.atan2(m13, m33); z = Math.atan2(m21, m22) }
208
- else { y = Math.atan2(-m31, m11); z = 0 }
209
- break
210
- case "ZXY":
211
- x = Math.asin(clamp1(m32))
212
- if (Math.abs(m32) < LIM) { y = Math.atan2(-m31, m33); z = Math.atan2(-m12, m22) }
213
- else { y = 0; z = Math.atan2(m21, m11) }
214
- break
215
- case "ZYX":
216
- y = Math.asin(-clamp1(m31))
217
- if (Math.abs(m31) < LIM) { x = Math.atan2(m32, m33); z = Math.atan2(m21, m11) }
218
- else { x = 0; z = Math.atan2(-m12, m22) }
219
- break
220
- case "YZX":
221
- z = Math.asin(clamp1(m21))
222
- if (Math.abs(m21) < LIM) { x = Math.atan2(-m23, m22); y = Math.atan2(-m31, m11) }
223
- else { x = 0; y = Math.atan2(m13, m33) }
224
- break
225
- case "XZY":
226
- z = Math.asin(-clamp1(m12))
227
- if (Math.abs(m12) < LIM) { x = Math.atan2(m32, m22); y = Math.atan2(m13, m11) }
228
- else { x = Math.atan2(-m23, m33); y = 0 }
229
- break
230
- }
231
- return new Vec3(x * RAD2DEG, y * RAD2DEG, z * RAD2DEG)
232
- }