@snaptrude/plugin-core 0.3.0 → 0.6.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 (302) hide show
  1. package/AGENTS.md +130 -48
  2. package/CHANGELOG.md +163 -0
  3. package/api-manifest.full.json +5600 -0
  4. package/api-manifest.json +5502 -0
  5. package/dist/api/analysis/heatmaps.d.ts +234 -0
  6. package/dist/api/analysis/heatmaps.d.ts.map +1 -0
  7. package/dist/api/analysis/illuminance.d.ts +145 -0
  8. package/dist/api/analysis/illuminance.d.ts.map +1 -0
  9. package/dist/api/analysis/index.d.ts +44 -0
  10. package/dist/api/analysis/index.d.ts.map +1 -0
  11. package/dist/api/analysis/shadows.d.ts +165 -0
  12. package/dist/api/analysis/shadows.d.ts.map +1 -0
  13. package/dist/api/analysis/sunlightHours.d.ts +208 -0
  14. package/dist/api/analysis/sunlightHours.d.ts.map +1 -0
  15. package/dist/api/analysis/sunpath.d.ts +80 -0
  16. package/dist/api/analysis/sunpath.d.ts.map +1 -0
  17. package/dist/api/core/buildings.d.ts +427 -0
  18. package/dist/api/core/buildings.d.ts.map +1 -0
  19. package/dist/api/core/comment/index.d.ts +230 -0
  20. package/dist/api/core/comment/index.d.ts.map +1 -0
  21. package/dist/api/core/geom/create/index.d.ts +247 -0
  22. package/dist/api/core/geom/create/index.d.ts.map +1 -0
  23. package/dist/api/core/geom/delete/index.d.ts +72 -0
  24. package/dist/api/core/geom/delete/index.d.ts.map +1 -0
  25. package/dist/api/core/geom/index.d.ts +24 -23
  26. package/dist/api/core/geom/index.d.ts.map +1 -1
  27. package/dist/api/core/geom/query/arc.d.ts +169 -0
  28. package/dist/api/core/geom/query/arc.d.ts.map +1 -0
  29. package/dist/api/core/geom/query/brep.d.ts +402 -0
  30. package/dist/api/core/geom/query/brep.d.ts.map +1 -0
  31. package/dist/api/core/geom/query/circle.d.ts +378 -0
  32. package/dist/api/core/geom/query/circle.d.ts.map +1 -0
  33. package/dist/api/core/geom/query/contour.d.ts +450 -0
  34. package/dist/api/core/geom/query/contour.d.ts.map +1 -0
  35. package/dist/api/core/geom/query/curve.d.ts +918 -0
  36. package/dist/api/core/geom/query/curve.d.ts.map +1 -0
  37. package/dist/api/core/geom/query/edge.d.ts +128 -0
  38. package/dist/api/core/geom/query/edge.d.ts.map +1 -0
  39. package/dist/api/core/geom/query/face.d.ts +363 -0
  40. package/dist/api/core/geom/query/face.d.ts.map +1 -0
  41. package/dist/api/core/geom/query/halfedge.d.ts +206 -0
  42. package/dist/api/core/geom/query/halfedge.d.ts.map +1 -0
  43. package/dist/api/core/geom/query/index.d.ts +61 -0
  44. package/dist/api/core/geom/query/index.d.ts.map +1 -0
  45. package/dist/api/core/geom/query/profile.d.ts +410 -0
  46. package/dist/api/core/geom/query/profile.d.ts.map +1 -0
  47. package/dist/api/core/geom/query/vertex.d.ts +187 -0
  48. package/dist/api/core/geom/query/vertex.d.ts.map +1 -0
  49. package/dist/api/core/geom/update/contour.d.ts +272 -0
  50. package/dist/api/core/geom/update/contour.d.ts.map +1 -0
  51. package/dist/api/core/geom/update/curve.d.ts +180 -0
  52. package/dist/api/core/geom/update/curve.d.ts.map +1 -0
  53. package/dist/api/core/geom/update/index.d.ts +27 -0
  54. package/dist/api/core/geom/update/index.d.ts.map +1 -0
  55. package/dist/api/core/geom/update/profile.d.ts +329 -0
  56. package/dist/api/core/geom/update/profile.d.ts.map +1 -0
  57. package/dist/api/core/groups.d.ts +485 -0
  58. package/dist/api/core/groups.d.ts.map +1 -0
  59. package/dist/api/core/history/index.d.ts +78 -0
  60. package/dist/api/core/history/index.d.ts.map +1 -0
  61. package/dist/api/core/index.d.ts +51 -1
  62. package/dist/api/core/index.d.ts.map +1 -1
  63. package/dist/api/core/io/import/index.d.ts +392 -0
  64. package/dist/api/core/io/import/index.d.ts.map +1 -0
  65. package/dist/api/core/io/index.d.ts +35 -0
  66. package/dist/api/core/io/index.d.ts.map +1 -0
  67. package/dist/api/core/io/job/index.d.ts +139 -0
  68. package/dist/api/core/io/job/index.d.ts.map +1 -0
  69. package/dist/api/core/io/query/index.d.ts +74 -0
  70. package/dist/api/core/io/query/index.d.ts.map +1 -0
  71. package/dist/api/core/io/terrain/index.d.ts +206 -0
  72. package/dist/api/core/io/terrain/index.d.ts.map +1 -0
  73. package/dist/api/core/io/underlay/index.d.ts +286 -0
  74. package/dist/api/core/io/underlay/index.d.ts.map +1 -0
  75. package/dist/api/core/layers.d.ts +402 -0
  76. package/dist/api/core/layers.d.ts.map +1 -0
  77. package/dist/api/core/math/quat.d.ts +111 -128
  78. package/dist/api/core/math/quat.d.ts.map +1 -1
  79. package/dist/api/core/math/vec3.d.ts +120 -102
  80. package/dist/api/core/math/vec3.d.ts.map +1 -1
  81. package/dist/api/core/project/index.d.ts +399 -0
  82. package/dist/api/core/project/index.d.ts.map +1 -0
  83. package/dist/api/core/tags.d.ts +755 -0
  84. package/dist/api/core/tags.d.ts.map +1 -0
  85. package/dist/api/core/units/index.d.ts +175 -0
  86. package/dist/api/core/units/index.d.ts.map +1 -0
  87. package/dist/api/core/zoom/index.d.ts +45 -0
  88. package/dist/api/core/zoom/index.d.ts.map +1 -0
  89. package/dist/api/design/boolean/index.d.ts +168 -0
  90. package/dist/api/design/boolean/index.d.ts.map +1 -0
  91. package/dist/api/design/create/index.d.ts +837 -0
  92. package/dist/api/design/create/index.d.ts.map +1 -0
  93. package/dist/api/design/delete/index.d.ts +63 -0
  94. package/dist/api/design/delete/index.d.ts.map +1 -0
  95. package/dist/api/design/doors/index.d.ts +268 -0
  96. package/dist/api/design/doors/index.d.ts.map +1 -0
  97. package/dist/api/design/edit/index.d.ts +49 -0
  98. package/dist/api/design/edit/index.d.ts.map +1 -0
  99. package/dist/api/design/erase/index.d.ts +160 -0
  100. package/dist/api/design/erase/index.d.ts.map +1 -0
  101. package/dist/api/design/furniture/index.d.ts +123 -0
  102. package/dist/api/design/furniture/index.d.ts.map +1 -0
  103. package/dist/api/design/index.d.ts +153 -0
  104. package/dist/api/design/index.d.ts.map +1 -0
  105. package/dist/api/design/lock.d.ts +41 -0
  106. package/dist/api/design/lock.d.ts.map +1 -0
  107. package/dist/api/design/materials/index.d.ts +297 -0
  108. package/dist/api/design/materials/index.d.ts.map +1 -0
  109. package/dist/api/design/query/geometry/index.d.ts +140 -0
  110. package/dist/api/design/query/geometry/index.d.ts.map +1 -0
  111. package/dist/api/design/query/index.d.ts +1011 -0
  112. package/dist/api/design/query/index.d.ts.map +1 -0
  113. package/dist/api/design/query/spaces.d.ts +221 -0
  114. package/dist/api/design/query/spaces.d.ts.map +1 -0
  115. package/dist/api/design/selection/index.d.ts +282 -0
  116. package/dist/api/design/selection/index.d.ts.map +1 -0
  117. package/dist/api/design/shared.d.ts +38 -0
  118. package/dist/api/design/shared.d.ts.map +1 -0
  119. package/dist/api/design/transform/index.d.ts +87 -0
  120. package/dist/api/design/transform/index.d.ts.map +1 -0
  121. package/dist/api/design/update/index.d.ts +178 -0
  122. package/dist/api/design/update/index.d.ts.map +1 -0
  123. package/dist/api/design/windows/index.d.ts +189 -0
  124. package/dist/api/design/windows/index.d.ts.map +1 -0
  125. package/dist/api/entity/buildableEnvelope.d.ts +261 -0
  126. package/dist/api/entity/buildableEnvelope.d.ts.map +1 -0
  127. package/dist/api/entity/department.d.ts +0 -98
  128. package/dist/api/entity/department.d.ts.map +1 -1
  129. package/dist/api/entity/index.d.ts +9 -9
  130. package/dist/api/entity/index.d.ts.map +1 -1
  131. package/dist/api/entity/referenceLine.d.ts +49 -106
  132. package/dist/api/entity/referenceLine.d.ts.map +1 -1
  133. package/dist/api/entity/space.d.ts +484 -251
  134. package/dist/api/entity/space.d.ts.map +1 -1
  135. package/dist/api/entity/story.d.ts +49 -39
  136. package/dist/api/entity/story.d.ts.map +1 -1
  137. package/dist/api/index.d.ts +22 -12
  138. package/dist/api/index.d.ts.map +1 -1
  139. package/dist/api/presentation/aiInspiration.d.ts +440 -0
  140. package/dist/api/presentation/aiInspiration.d.ts.map +1 -0
  141. package/dist/api/presentation/diagrams.d.ts +81 -0
  142. package/dist/api/presentation/diagrams.d.ts.map +1 -0
  143. package/dist/api/presentation/import.d.ts +113 -0
  144. package/dist/api/presentation/import.d.ts.map +1 -0
  145. package/dist/api/presentation/index.d.ts +46 -0
  146. package/dist/api/presentation/index.d.ts.map +1 -0
  147. package/dist/api/presentation/sheets.d.ts +176 -0
  148. package/dist/api/presentation/sheets.d.ts.map +1 -0
  149. package/dist/api/presentation/views.d.ts +296 -0
  150. package/dist/api/presentation/views.d.ts.map +1 -0
  151. package/dist/api/program/adjacency.d.ts +155 -0
  152. package/dist/api/program/adjacency.d.ts.map +1 -0
  153. package/dist/api/program/areas.d.ts +360 -0
  154. package/dist/api/program/areas.d.ts.map +1 -0
  155. package/dist/api/program/classification.d.ts +135 -0
  156. package/dist/api/program/classification.d.ts.map +1 -0
  157. package/dist/api/program/cores.d.ts +174 -0
  158. package/dist/api/program/cores.d.ts.map +1 -0
  159. package/dist/api/program/departments.d.ts +431 -0
  160. package/dist/api/program/departments.d.ts.map +1 -0
  161. package/dist/api/program/index.d.ts +69 -0
  162. package/dist/api/program/index.d.ts.map +1 -0
  163. package/dist/api/program/layout.d.ts +63 -0
  164. package/dist/api/program/layout.d.ts.map +1 -0
  165. package/dist/api/program/metrics.d.ts +108 -0
  166. package/dist/api/program/metrics.d.ts.map +1 -0
  167. package/dist/api/program/site.d.ts +451 -0
  168. package/dist/api/program/site.d.ts.map +1 -0
  169. package/dist/api/program/spreadsheet.d.ts +2041 -0
  170. package/dist/api/program/spreadsheet.d.ts.map +1 -0
  171. package/dist/handles.d.ts +171 -0
  172. package/dist/handles.d.ts.map +1 -0
  173. package/dist/host-utils.d.ts +7 -5
  174. package/dist/host-utils.d.ts.map +1 -1
  175. package/dist/index.cjs +4344 -899
  176. package/dist/index.cjs.map +1 -1
  177. package/dist/index.d.ts +1 -0
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +3682 -865
  180. package/dist/index.js.map +1 -1
  181. package/package.json +6 -2
  182. package/scripts/generate-manifest.mjs +193 -0
  183. package/scripts/generate-manifest.test.mjs +215 -0
  184. package/src/api/analysis/heatmaps.ts +256 -0
  185. package/src/api/analysis/illuminance.ts +155 -0
  186. package/src/api/analysis/index.ts +46 -0
  187. package/src/api/analysis/shadows.ts +183 -0
  188. package/src/api/analysis/sunlightHours.ts +211 -0
  189. package/src/api/analysis/sunpath.ts +83 -0
  190. package/src/api/core/buildings.ts +485 -0
  191. package/src/api/core/comment/index.ts +258 -0
  192. package/src/api/core/geom/create/index.ts +293 -0
  193. package/src/api/core/geom/delete/index.ts +78 -0
  194. package/src/api/core/geom/index.ts +24 -23
  195. package/src/api/core/geom/query/arc.ts +169 -0
  196. package/src/api/core/geom/query/brep.ts +444 -0
  197. package/src/api/core/geom/query/circle.ts +404 -0
  198. package/src/api/core/geom/query/contour.ts +540 -0
  199. package/src/api/core/geom/query/curve.ts +1078 -0
  200. package/src/api/core/geom/query/edge.ts +130 -0
  201. package/src/api/core/geom/query/face.ts +403 -0
  202. package/src/api/core/geom/query/halfedge.ts +210 -0
  203. package/src/api/core/geom/query/index.ts +63 -0
  204. package/src/api/core/geom/query/profile.ts +473 -0
  205. package/src/api/core/geom/query/vertex.ts +205 -0
  206. package/src/api/core/geom/update/contour.ts +315 -0
  207. package/src/api/core/geom/update/curve.ts +209 -0
  208. package/src/api/core/geom/update/index.ts +29 -0
  209. package/src/api/core/geom/update/profile.ts +377 -0
  210. package/src/api/core/groups.ts +521 -0
  211. package/src/api/core/history/index.ts +84 -0
  212. package/src/api/core/index.ts +51 -1
  213. package/src/api/core/io/import/index.ts +432 -0
  214. package/src/api/core/io/index.ts +37 -0
  215. package/src/api/core/io/job/index.ts +140 -0
  216. package/src/api/core/io/query/index.ts +71 -0
  217. package/src/api/core/io/terrain/index.ts +214 -0
  218. package/src/api/core/io/underlay/index.ts +295 -0
  219. package/src/api/core/layers.ts +333 -0
  220. package/src/api/core/math/quat.ts +112 -235
  221. package/src/api/core/math/vec3.ts +124 -159
  222. package/src/api/core/project/index.ts +418 -0
  223. package/src/api/core/tags.ts +808 -0
  224. package/src/api/core/units/index.ts +164 -0
  225. package/src/api/core/zoom/index.ts +47 -0
  226. package/src/api/design/boolean/index.ts +179 -0
  227. package/src/api/design/create/index.ts +895 -0
  228. package/src/api/design/delete/index.ts +67 -0
  229. package/src/api/design/doors/index.ts +285 -0
  230. package/src/api/design/edit/index.ts +54 -0
  231. package/src/api/design/erase/index.ts +151 -0
  232. package/src/api/design/furniture/index.ts +130 -0
  233. package/src/api/design/index.ts +162 -0
  234. package/src/api/design/lock.ts +42 -0
  235. package/src/api/design/materials/index.ts +301 -0
  236. package/src/api/design/query/geometry/index.ts +166 -0
  237. package/src/api/design/query/index.ts +937 -0
  238. package/src/api/design/query/spaces.ts +132 -0
  239. package/src/api/design/selection/index.ts +273 -0
  240. package/src/api/design/shared.ts +40 -0
  241. package/src/api/design/transform/index.ts +93 -0
  242. package/src/api/design/update/index.ts +117 -0
  243. package/src/api/design/windows/index.ts +207 -0
  244. package/src/api/entity/buildableEnvelope.ts +318 -0
  245. package/src/api/entity/department.ts +0 -113
  246. package/src/api/entity/index.ts +9 -9
  247. package/src/api/entity/referenceLine.ts +50 -38
  248. package/src/api/entity/space.ts +285 -226
  249. package/src/api/entity/story.ts +53 -42
  250. package/src/api/index.ts +22 -12
  251. package/src/api/presentation/aiInspiration.ts +362 -0
  252. package/src/api/presentation/diagrams.ts +84 -0
  253. package/src/api/presentation/import.ts +112 -0
  254. package/src/api/presentation/index.ts +48 -0
  255. package/src/api/presentation/sheets.ts +198 -0
  256. package/src/api/presentation/views.ts +303 -0
  257. package/src/api/program/adjacency.ts +164 -0
  258. package/src/api/program/areas.ts +335 -0
  259. package/src/api/program/classification.ts +138 -0
  260. package/src/api/program/cores.ts +171 -0
  261. package/src/api/program/departments.ts +465 -0
  262. package/src/api/program/index.ts +71 -0
  263. package/src/api/program/layout.ts +68 -0
  264. package/src/api/program/metrics.ts +120 -0
  265. package/src/api/program/site.ts +419 -0
  266. package/src/api/program/spreadsheet.ts +2075 -0
  267. package/src/handles.ts +194 -0
  268. package/src/host-utils.ts +10 -6
  269. package/src/index.ts +1 -0
  270. package/dist/api/core/geom/arc.d.ts +0 -81
  271. package/dist/api/core/geom/arc.d.ts.map +0 -1
  272. package/dist/api/core/geom/curve.d.ts +0 -70
  273. package/dist/api/core/geom/curve.d.ts.map +0 -1
  274. package/dist/api/core/geom/line.d.ts +0 -56
  275. package/dist/api/core/geom/line.d.ts.map +0 -1
  276. package/dist/api/core/geom/profile.d.ts +0 -121
  277. package/dist/api/core/geom/profile.d.ts.map +0 -1
  278. package/dist/api/tools/copy.d.ts +0 -59
  279. package/dist/api/tools/copy.d.ts.map +0 -1
  280. package/dist/api/tools/index.d.ts +0 -33
  281. package/dist/api/tools/index.d.ts.map +0 -1
  282. package/dist/api/tools/material.d.ts +0 -51
  283. package/dist/api/tools/material.d.ts.map +0 -1
  284. package/dist/api/tools/offset.d.ts +0 -43
  285. package/dist/api/tools/offset.d.ts.map +0 -1
  286. package/dist/api/tools/selection.d.ts +0 -48
  287. package/dist/api/tools/selection.d.ts.map +0 -1
  288. package/dist/api/tools/transform.d.ts +0 -114
  289. package/dist/api/tools/transform.d.ts.map +0 -1
  290. package/dist/api/units/index.d.ts +0 -163
  291. package/dist/api/units/index.d.ts.map +0 -1
  292. package/src/api/core/geom/arc.ts +0 -70
  293. package/src/api/core/geom/curve.ts +0 -41
  294. package/src/api/core/geom/line.ts +0 -53
  295. package/src/api/core/geom/profile.ts +0 -94
  296. package/src/api/tools/copy.ts +0 -55
  297. package/src/api/tools/index.ts +0 -39
  298. package/src/api/tools/material.ts +0 -49
  299. package/src/api/tools/offset.ts +0 -43
  300. package/src/api/tools/selection.ts +0 -51
  301. package/src/api/tools/transform.ts +0 -117
  302. package/src/api/units/index.ts +0 -163
@@ -1,295 +1,172 @@
1
- import * as z from "zod"
2
- import type { PVec3 } from "./vec3"
1
+ import { PluginApiReturn } from "../../../types"
2
+ import { Vec3Handle, QuatHandle, QuatComponents } from "../../../handles"
3
3
 
4
4
  /**
5
- * Quaternion operations for 3D rotations.
5
+ * Quaternion operations (all-handle model, §11).
6
6
  *
7
- * Quaternions avoid gimbal lock and provide smooth interpolation
8
- * compared to Euler angles. All methods are **pure** — they return
9
- * new {@linkcode PQuat} values without mutating the inputs.
10
- *
11
- * Accessed via `snaptrude.core.math.quat`.
7
+ * Quaternions are opaque {@linkcode QuatHandle}s; every operation is a host call
8
+ * returning a new handle. Read primitive components back with
9
+ * {@linkcode PluginQuatApi.components}. Accessed via `snaptrude.core.math.quat`.
12
10
  */
13
11
  export abstract class PluginQuatApi {
14
12
  constructor() {}
15
13
 
16
14
  /**
17
- * Create a new quaternion from raw components.
18
- *
19
- * For most use cases prefer {@linkcode PluginQuatApi.fromAxisAngle}
20
- * or {@linkcode PluginQuatApi.fromEuler} instead.
15
+ * Create a quaternion from primitive components.
21
16
  *
22
- * @param x - The X component
23
- * @param y - The Y component
24
- * @param z - The Z component
25
- * @param w - The W (scalar) component
26
- * @returns A new {@linkcode PQuat}
17
+ * # Example
18
+ * ```ts
19
+ * const q = await snaptrude.core.math.quat.new(0, 0, 0, 1)
20
+ * const { x, y, z, w } = await snaptrude.core.math.quat.components(q)
21
+ * ```
27
22
  */
28
- new(x: number, y: number, z: number, w: number): PQuat {
29
- return { x, y, z, w }
30
- }
31
-
23
+ abstract new(x: number, y: number, z: number, w: number): PluginApiReturn<QuatHandle>
32
24
  /**
33
- * Create an identity quaternion representing no rotation.
25
+ * Return the identity quaternion (no rotation).
34
26
  *
35
- * @returns `{ x: 0, y: 0, z: 0, w: 1 }`
27
+ * # Example
28
+ * ```ts
29
+ * const noRotation = await snaptrude.core.math.quat.identity()
30
+ * ```
36
31
  */
37
- identity(): PQuat {
38
- return { x: 0, y: 0, z: 0, w: 1 }
39
- }
40
-
32
+ abstract identity(): PluginApiReturn<QuatHandle>
41
33
  /**
42
- * Create a quaternion from an axis and an angle.
43
- *
44
- * @param axis - The rotation axis as a {@linkcode PVec3} (will be normalized internally)
45
- * @param angle - The rotation angle in **radians**
46
- * @returns A new unit {@linkcode PQuat}, or identity if {@linkcode axis} has zero length
34
+ * Build a quaternion from a rotation axis and an angle in radians.
47
35
  *
48
36
  * # Example
49
37
  * ```ts
50
- * const { vec3, quat } = snaptrude.core.math
51
- * // 90° rotation around the Y axis
52
- * const rot = quat.fromAxisAngle(vec3.new(0, 1, 0), Math.PI / 2)
38
+ * const axis = await snaptrude.core.math.vec3.new(0, 0, 1)
39
+ * const quarterTurn = await snaptrude.core.math.quat.fromAxisAngle(axis, Math.PI / 2)
53
40
  * ```
54
41
  */
55
- fromAxisAngle(axis: PVec3, angle: number): PQuat {
56
- const halfAngle = angle / 2
57
- const s = Math.sin(halfAngle)
58
- const len = Math.sqrt(axis.x * axis.x + axis.y * axis.y + axis.z * axis.z)
59
- if (len === 0) return { x: 0, y: 0, z: 0, w: 1 }
60
- return {
61
- x: (axis.x / len) * s,
62
- y: (axis.y / len) * s,
63
- z: (axis.z / len) * s,
64
- w: Math.cos(halfAngle),
65
- }
66
- }
67
-
42
+ abstract fromAxisAngle(axis: Vec3Handle, angle: number): PluginApiReturn<QuatHandle>
68
43
  /**
69
- * Create a quaternion from Euler angles in **XYZ** rotation order.
44
+ * Build a quaternion from Euler angles in radians.
70
45
  *
71
- * @param x - Rotation around X axis in **radians**
72
- * @param y - Rotation around Y axis in **radians**
73
- * @param z - Rotation around Z axis in **radians**
74
- * @returns A new {@linkcode PQuat}
46
+ * # Example
47
+ * ```ts
48
+ * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)
49
+ * ```
75
50
  */
76
- fromEuler(x: number, y: number, z: number): PQuat {
77
- const cx = Math.cos(x / 2)
78
- const sx = Math.sin(x / 2)
79
- const cy = Math.cos(y / 2)
80
- const sy = Math.sin(y / 2)
81
- const cz = Math.cos(z / 2)
82
- const sz = Math.sin(z / 2)
83
- return {
84
- x: sx * cy * cz + cx * sy * sz,
85
- y: cx * sy * cz - sx * cy * sz,
86
- z: cx * cy * sz + sx * sy * cz,
87
- w: cx * cy * cz - sx * sy * sz,
88
- }
89
- }
90
-
51
+ abstract fromEuler(x: number, y: number, z: number): PluginApiReturn<QuatHandle>
91
52
  /**
92
- * Multiply two quaternions, combining their rotations.
53
+ * Compose two rotations with the Hamilton product `a * b` (apply `b` then `a`).
93
54
  *
94
- * Quaternion multiplication is **not commutative**: `a * b ≠ b * a`.
95
- * The result applies rotation {@linkcode b} first, then {@linkcode a}.
96
- *
97
- * @param a - First quaternion (applied second)
98
- * @param b - Second quaternion (applied first)
99
- * @returns A new {@linkcode PQuat} representing the combined rotation
55
+ * # Example
56
+ * ```ts
57
+ * const a = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)
58
+ * const b = await snaptrude.core.math.quat.fromEuler(Math.PI / 4, 0, 0)
59
+ * const combined = await snaptrude.core.math.quat.multiply(a, b) // b first, then a
60
+ * ```
100
61
  */
101
- multiply(a: PQuat, b: PQuat): PQuat {
102
- return {
103
- x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
104
- y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
105
- z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
106
- w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
107
- }
108
- }
109
-
62
+ abstract multiply(a: QuatHandle, b: QuatHandle): PluginApiReturn<QuatHandle>
110
63
  /**
111
- * Compute the conjugate of a quaternion.
64
+ * Compute the conjugate of a quaternion (negated vector part).
112
65
  *
113
- * For unit quaternions the conjugate equals the inverse.
114
- *
115
- * @param q - The quaternion
116
- * @returns A new {@linkcode PQuat} with negated vector part `(-x, -y, -z, w)`
66
+ * # Example
67
+ * ```ts
68
+ * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 4, 0)
69
+ * const conj = await snaptrude.core.math.quat.conjugate(q)
70
+ * ```
117
71
  */
118
- conjugate(q: PQuat): PQuat {
119
- return { x: -q.x, y: -q.y, z: -q.z, w: q.w }
120
- }
121
-
72
+ abstract conjugate(q: QuatHandle): PluginApiReturn<QuatHandle>
122
73
  /**
123
- * Compute the length (magnitude) of a quaternion.
74
+ * Compute the magnitude (norm) of a quaternion.
124
75
  *
125
- * @param q - The quaternion
126
- * @returns The magnitude `√(x² + y² + z² + w²)`
76
+ * # Example
77
+ * ```ts
78
+ * const q = await snaptrude.core.math.quat.new(0, 0, 0, 1)
79
+ * const len = await snaptrude.core.math.quat.length(q) // 1
80
+ * ```
127
81
  */
128
- length(q: PQuat): number {
129
- return Math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w)
130
- }
131
-
82
+ abstract length(q: QuatHandle): PluginApiReturn<number>
132
83
  /**
133
84
  * Normalize a quaternion to unit length.
134
85
  *
135
- * @param q - The quaternion to normalize
136
- * @returns A new unit-length {@linkcode PQuat}, or identity if the input has zero length
86
+ * # Example
87
+ * ```ts
88
+ * const q = await snaptrude.core.math.quat.new(0, 0, 1, 1)
89
+ * const unit = await snaptrude.core.math.quat.normalize(q)
90
+ * ```
137
91
  */
138
- normalize(q: PQuat): PQuat {
139
- const len = this.length(q)
140
- if (len === 0) return { x: 0, y: 0, z: 0, w: 1 }
141
- return { x: q.x / len, y: q.y / len, z: q.z / len, w: q.w / len }
142
- }
143
-
92
+ abstract normalize(q: QuatHandle): PluginApiReturn<QuatHandle>
144
93
  /**
145
- * Compute the inverse of a quaternion.
94
+ * Compute the inverse quaternion the rotation that undoes `q`.
146
95
  *
147
- * The inverse satisfies `q * inverse(q) = identity`.
148
- *
149
- * @param q - The quaternion to invert
150
- * @returns A new {@linkcode PQuat} that is the multiplicative inverse,
151
- * or identity if the input has zero length
96
+ * # Example
97
+ * ```ts
98
+ * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)
99
+ * const undo = await snaptrude.core.math.quat.inverse(q)
100
+ * ```
152
101
  */
153
- inverse(q: PQuat): PQuat {
154
- const lenSq = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w
155
- if (lenSq === 0) return { x: 0, y: 0, z: 0, w: 1 }
156
- return { x: -q.x / lenSq, y: -q.y / lenSq, z: -q.z / lenSq, w: q.w / lenSq }
157
- }
158
-
102
+ abstract inverse(q: QuatHandle): PluginApiReturn<QuatHandle>
159
103
  /**
160
- * Rotate a 3D vector by a quaternion.
161
- *
162
- * Computes `q * v * conjugate(q)` using the Hamilton product.
163
- *
164
- * @param q - The rotation quaternion (should be unit-length)
165
- * @param v - The vector to rotate as a {@linkcode PVec3}
166
- * @returns A new rotated {@linkcode PVec3}
104
+ * Decompose a quaternion into its rotation axis and angle (radians).
167
105
  *
168
106
  * # Example
169
107
  * ```ts
170
- * const { vec3, quat } = snaptrude.core.math
171
- * const rot = quat.fromAxisAngle(vec3.new(0, 1, 0), Math.PI / 2)
172
- * const rotated = quat.rotateVec3(rot, vec3.new(1, 0, 0))
173
- * // ≈ { x: 0, y: 0, z: -1 }
108
+ * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 3, 0)
109
+ * const { axis, angle } = await snaptrude.core.math.quat.toAxisAngle(q)
110
+ * const { x, y, z } = await snaptrude.core.math.vec3.components(axis)
174
111
  * ```
175
112
  */
176
- rotateVec3(q: PQuat, v: PVec3): PVec3 {
177
- const vq: PQuat = { x: v.x, y: v.y, z: v.z, w: 0 }
178
- const conj = this.conjugate(q)
179
- const result = this.multiply(this.multiply(q, vq), conj)
180
- return { x: result.x, y: result.y, z: result.z }
181
- }
182
-
113
+ abstract toAxisAngle(q: QuatHandle): PluginApiReturn<{ axis: Vec3Handle; angle: number }>
183
114
  /**
184
- * Convert a quaternion to axis-angle representation.
115
+ * Spherically interpolate (slerp) between two rotations by factor `t`.
185
116
  *
186
- * @param q - The quaternion to convert
187
- * @returns An object with:
188
- * - `axis` The rotation axis as a unit {@linkcode PVec3}
189
- * (defaults to `(1, 0, 0)` when angle is zero)
190
- * - `angle` The rotation angle in **radians**
117
+ * # Example
118
+ * ```ts
119
+ * const start = await snaptrude.core.math.quat.identity()
120
+ * const end = await snaptrude.core.math.quat.fromEuler(0, Math.PI, 0)
121
+ * const halfway = await snaptrude.core.math.quat.slerp(start, end, 0.5)
122
+ * ```
191
123
  */
192
- toAxisAngle(q: PQuat): { axis: PVec3; angle: number } {
193
- const nq = this.normalize(q)
194
- const angle = 2 * Math.acos(Math.min(1, Math.max(-1, nq.w)))
195
- const s = Math.sin(angle / 2)
196
- if (s < 1e-6) {
197
- return { axis: { x: 1, y: 0, z: 0 }, angle: 0 }
198
- }
199
- return {
200
- axis: { x: nq.x / s, y: nq.y / s, z: nq.z / s },
201
- angle,
202
- }
203
- }
204
-
124
+ abstract slerp(a: QuatHandle, b: QuatHandle, t: number): PluginApiReturn<QuatHandle>
205
125
  /**
206
- * Spherical linear interpolation between two quaternions.
207
- *
208
- * Produces smooth constant-speed rotation between {@linkcode a} and {@linkcode b}.
126
+ * Compute the dot product of two quaternions.
209
127
  *
210
- * @param a - Start quaternion (returned when `t = 0`)
211
- * @param b - End quaternion (returned when `t = 1`)
212
- * @param t - Interpolation factor, typically in `[0, 1]`
213
- * @returns A new interpolated {@linkcode PQuat}
128
+ * # Example
129
+ * ```ts
130
+ * const a = await snaptrude.core.math.quat.identity()
131
+ * const b = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)
132
+ * const d = await snaptrude.core.math.quat.dot(a, b)
133
+ * ```
214
134
  */
215
- slerp(a: PQuat, b: PQuat, t: number): PQuat {
216
- let cosHalf = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w
217
- let bx = b.x, by = b.y, bz = b.z, bw = b.w
218
- if (cosHalf < 0) {
219
- cosHalf = -cosHalf
220
- bx = -bx; by = -by; bz = -bz; bw = -bw
221
- }
222
- if (cosHalf >= 1.0) {
223
- return { x: a.x, y: a.y, z: a.z, w: a.w }
224
- }
225
- const halfAngle = Math.acos(cosHalf)
226
- const sinHalf = Math.sin(halfAngle)
227
- const ratioA = Math.sin((1 - t) * halfAngle) / sinHalf
228
- const ratioB = Math.sin(t * halfAngle) / sinHalf
229
- return {
230
- x: a.x * ratioA + bx * ratioB,
231
- y: a.y * ratioA + by * ratioB,
232
- z: a.z * ratioA + bz * ratioB,
233
- w: a.w * ratioA + bw * ratioB,
234
- }
235
- }
236
-
135
+ abstract dot(a: QuatHandle, b: QuatHandle): PluginApiReturn<number>
237
136
  /**
238
- * Compute the dot product of two quaternions.
239
- *
240
- * A value close to `1` or `-1` indicates similar orientations;
241
- * a value close to `0` indicates maximally different orientations.
137
+ * Test whether two quaternions have exactly equal components.
242
138
  *
243
- * @param a - First quaternion
244
- * @param b - Second quaternion
245
- * @returns The scalar dot product
139
+ * # Example
140
+ * ```ts
141
+ * const a = await snaptrude.core.math.quat.new(0, 0, 0, 1)
142
+ * const b = await snaptrude.core.math.quat.identity()
143
+ * const same = await snaptrude.core.math.quat.equals(a, b) // true
144
+ * ```
246
145
  */
247
- dot(a: PQuat, b: PQuat): number {
248
- return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w
249
- }
250
-
146
+ abstract equals(a: QuatHandle, b: QuatHandle): PluginApiReturn<boolean>
251
147
  /**
252
- * Check if two quaternions are exactly equal (strict equality per component).
253
- *
254
- * For floating-point comparisons, prefer {@linkcode PluginQuatApi.equalsApprox}.
148
+ * Test whether two quaternions are equal within a tolerance `epsilon` (default `1e-6`).
255
149
  *
256
- * @param a - First quaternion
257
- * @param b - Second quaternion
258
- * @returns `true` if all components match exactly
150
+ * # Example
151
+ * ```ts
152
+ * const a = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)
153
+ * const b = await snaptrude.core.math.quat.fromEuler(0, 1.5711, 0)
154
+ * const close = await snaptrude.core.math.quat.equalsApprox(a, b, 1e-3) // true
155
+ * ```
259
156
  */
260
- equals(a: PQuat, b: PQuat): boolean {
261
- return a.x === b.x && a.y === b.y && a.z === b.z && a.w === b.w
262
- }
263
-
157
+ abstract equalsApprox(
158
+ a: QuatHandle,
159
+ b: QuatHandle,
160
+ epsilon?: number,
161
+ ): PluginApiReturn<boolean>
264
162
  /**
265
- * Check if two quaternions are approximately equal within a tolerance.
163
+ * Read the primitive `{ x, y, z, w }` components of a quaternion handle.
266
164
  *
267
- * @param a - First quaternion
268
- * @param b - Second quaternion
269
- * @param epsilon - Maximum allowed difference per component (default `1e-6`)
270
- * @returns `true` if `|a[i] - b[i]| < epsilon` for all components
165
+ * # Example
166
+ * ```ts
167
+ * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)
168
+ * const { x, y, z, w } = await snaptrude.core.math.quat.components(q)
169
+ * ```
271
170
  */
272
- equalsApprox(a: PQuat, b: PQuat, epsilon: number = 1e-6): boolean {
273
- return (
274
- Math.abs(a.x - b.x) < epsilon &&
275
- Math.abs(a.y - b.y) < epsilon &&
276
- Math.abs(a.z - b.z) < epsilon &&
277
- Math.abs(a.w - b.w) < epsilon
278
- )
279
- }
171
+ abstract components(q: QuatHandle): PluginApiReturn<QuatComponents>
280
172
  }
281
-
282
- /**
283
- * A quaternion with `x`, `y`, `z`, and `w` components.
284
- *
285
- * Used for representing 3D rotations without gimbal lock.
286
- * Equivalent to `BABYLON.Quaternion`.
287
- */
288
- export const PQuat = z.object({
289
- x: z.number(),
290
- y: z.number(),
291
- z: z.number(),
292
- w: z.number(),
293
- })
294
-
295
- export type PQuat = z.infer<typeof PQuat>