lecodes-cli 0.19.0 → 0.20.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 (270) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +1069 -396
  3. package/package.json +14 -13
  4. package/runtime/scene-harness.json +1 -1
  5. package/runtime/sdk-types.json +1 -1
  6. package/runtime/web/assets/Roboto-Variable-DHm9jpd-.woff2 +0 -0
  7. package/runtime/web/assets/__vite-browser-external-BIHI7g3E.js +1 -0
  8. package/runtime/web/assets/basis-C64VHDVD.js +1 -0
  9. package/runtime/web/assets/basis_transcoder-VXdx5NbI.wasm +0 -0
  10. package/runtime/web/assets/createViewerLite-BvHobVhp.js +852 -0
  11. package/runtime/web/assets/draco-BiISTFcR.js +118 -0
  12. package/runtime/web/assets/draco_decoder-DsQ12WqX.wasm +0 -0
  13. package/runtime/web/assets/index-CfNCCBjN.js +2 -0
  14. package/runtime/web/assets/mapViewImpl-B2JcES8l.js +810 -0
  15. package/runtime/web/assets/maplibre-gl-worker-CJfwIrte.js +8 -0
  16. package/runtime/web/assets/neutral_ibl128-D-lzdkLN.ktx +0 -0
  17. package/runtime/web/assets/worker-Caf-yYEI.js +2 -0
  18. package/runtime/web/embed.html +32 -0
  19. package/runtime/web/embed.js +171 -0
  20. package/src/api.ts +302 -0
  21. package/src/browserAuth.ts +87 -0
  22. package/src/cmgenTool.ts +104 -0
  23. package/src/commands/app.ts +896 -0
  24. package/src/commands/appAndroid.ts +603 -0
  25. package/src/commands/appDesktop.ts +339 -0
  26. package/src/commands/appDesktopMac.ts +470 -0
  27. package/src/commands/appIcon.ts +187 -0
  28. package/src/commands/appShared.ts +542 -0
  29. package/src/commands/appTemplates.ts +907 -0
  30. package/src/commands/appTemplatesAndroid.ts +599 -0
  31. package/src/commands/appTemplatesGradlew.ts +9 -0
  32. package/src/commands/assets.ts +28 -0
  33. package/src/commands/clone.ts +60 -0
  34. package/src/commands/compile.ts +253 -0
  35. package/src/commands/create.ts +59 -0
  36. package/src/commands/design.ts +863 -0
  37. package/src/commands/designTemplates.ts +11 -0
  38. package/src/commands/desktop.ts +127 -0
  39. package/src/commands/dev.ts +236 -0
  40. package/src/commands/diff.ts +59 -0
  41. package/src/commands/init.ts +191 -0
  42. package/src/commands/install.ts +198 -0
  43. package/src/commands/lightmap.ts +290 -0
  44. package/src/commands/link.ts +147 -0
  45. package/src/commands/login.ts +24 -0
  46. package/src/commands/navmesh.ts +225 -0
  47. package/src/commands/pn.ts +305 -0
  48. package/src/commands/projectTemplates.ts +130 -0
  49. package/src/commands/pull.ts +109 -0
  50. package/src/commands/push.ts +173 -0
  51. package/src/commands/render.ts +416 -0
  52. package/src/commands/scene.ts +148 -0
  53. package/src/commands/shaders.ts +157 -0
  54. package/src/commands/status.ts +29 -0
  55. package/src/commands/test.ts +371 -0
  56. package/src/commands/thumbs.ts +178 -0
  57. package/src/commands/types.ts +87 -0
  58. package/src/commands/update.ts +190 -0
  59. package/src/compile/assetIcons.ts +214 -0
  60. package/src/compile/collect.ts +46 -0
  61. package/src/compile/collectLocal.ts +37 -0
  62. package/src/compile/designCompile.ts +104 -0
  63. package/src/compile/fonts.ts +156 -0
  64. package/src/compile/headlessBundle.ts +129 -0
  65. package/src/compile/nativeStack.ts +21 -0
  66. package/src/compile/projectCompile.ts +109 -0
  67. package/src/compile/sceneCompile.ts +113 -0
  68. package/src/compile/screenEntry.ts +127 -0
  69. package/src/compile/shaders.ts +245 -0
  70. package/src/config.ts +42 -0
  71. package/src/designMeta.ts +35 -0
  72. package/src/desktopRenderer.ts +545 -0
  73. package/src/desktopScript.ts +276 -0
  74. package/src/dev/clientTemplates.ts +160 -0
  75. package/src/dev/devServer.ts +333 -0
  76. package/src/dev/webRunner.ts +22 -0
  77. package/src/dev/wsServer.ts +144 -0
  78. package/src/distRoot.ts +20 -0
  79. package/src/ignore.ts +163 -0
  80. package/src/index.ts +494 -0
  81. package/src/lecodes-3d-editor.d.ts +41 -0
  82. package/src/lecodes-assets.d.ts +7 -0
  83. package/src/lecodes-design.d.ts +191 -0
  84. package/src/lecodes-renderer.d.ts +131 -0
  85. package/src/localFiles.ts +144 -0
  86. package/src/manifest.ts +46 -0
  87. package/src/matcTool.ts +137 -0
  88. package/src/peers.ts +40 -0
  89. package/src/project.ts +61 -0
  90. package/src/projectEnv.ts +94 -0
  91. package/src/qrcode-terminal.d.ts +9 -0
  92. package/src/releases.ts +125 -0
  93. package/src/serverDiff.ts +78 -0
  94. package/src/textDiff.ts +103 -0
  95. package/src/types.ts +0 -0
  96. package/src/util.ts +146 -0
  97. package/runtime/sdk/animate/animate.ts +0 -238
  98. package/runtime/sdk/animate/bezier.ts +0 -138
  99. package/runtime/sdk/animate/easings.ts +0 -126
  100. package/runtime/sdk/canvas/Canvas.ts +0 -305
  101. package/runtime/sdk/compile/aspectMacro.ts +0 -86
  102. package/runtime/sdk/compile/assetIconMacro.ts +0 -384
  103. package/runtime/sdk/compile/assetMacro.ts +0 -146
  104. package/runtime/sdk/compile/assetName.ts +0 -50
  105. package/runtime/sdk/compile/bundler.ts +0 -287
  106. package/runtime/sdk/compile/compileProject.ts +0 -129
  107. package/runtime/sdk/compile/detectEntry.ts +0 -128
  108. package/runtime/sdk/compile/fontMacro.ts +0 -459
  109. package/runtime/sdk/compile/fontRegistry.ts +0 -78
  110. package/runtime/sdk/compile/header.ts +0 -67
  111. package/runtime/sdk/compile/index.ts +0 -100
  112. package/runtime/sdk/compile/libraryImports.ts +0 -52
  113. package/runtime/sdk/compile/liteMaterial.ts +0 -247
  114. package/runtime/sdk/compile/sceneEditor.ts +0 -88
  115. package/runtime/sdk/compile/serverSplit.ts +0 -233
  116. package/runtime/sdk/compile/serverTypes.ts +0 -227
  117. package/runtime/sdk/compile/sfnt.ts +0 -98
  118. package/runtime/sdk/compile/shaderSchema.ts +0 -202
  119. package/runtime/sdk/compile/shaderTargets.ts +0 -81
  120. package/runtime/sdk/compile/sourcemap.ts +0 -25
  121. package/runtime/sdk/core/Aspect.ts +0 -568
  122. package/runtime/sdk/core/InspectorUI.ts +0 -212
  123. package/runtime/sdk/core/StateMachine.ts +0 -308
  124. package/runtime/sdk/core/color.ts +0 -66
  125. package/runtime/sdk/core/compWrite.ts +0 -42
  126. package/runtime/sdk/core/events.ts +0 -38
  127. package/runtime/sdk/core/fields.ts +0 -120
  128. package/runtime/sdk/core/registry.ts +0 -23
  129. package/runtime/sdk/core/signals.ts +0 -277
  130. package/runtime/sdk/core/time.ts +0 -84
  131. package/runtime/sdk/g2/Camera2D.ts +0 -40
  132. package/runtime/sdk/g2/CharacterController2D.ts +0 -276
  133. package/runtime/sdk/g2/Node2D.ts +0 -267
  134. package/runtime/sdk/g2/OneWay2D.ts +0 -66
  135. package/runtime/sdk/g2/Physics2D.ts +0 -346
  136. package/runtime/sdk/g2/Scene2D.ts +0 -209
  137. package/runtime/sdk/g2/Shape2D.ts +0 -259
  138. package/runtime/sdk/g2/Sprite.ts +0 -89
  139. package/runtime/sdk/g2/SpriteAnimation.ts +0 -171
  140. package/runtime/sdk/g2/SpriteSheet.ts +0 -166
  141. package/runtime/sdk/g2/Texture2D.ts +0 -47
  142. package/runtime/sdk/g2/Tilemap.ts +0 -41
  143. package/runtime/sdk/g2/Tileset.ts +0 -71
  144. package/runtime/sdk/g2/Trigger2D.ts +0 -77
  145. package/runtime/sdk/g2/autotile.ts +0 -433
  146. package/runtime/sdk/g2/cells.ts +0 -91
  147. package/runtime/sdk/g2/defineScene2d.ts +0 -381
  148. package/runtime/sdk/g2/groups2d.ts +0 -106
  149. package/runtime/sdk/g2/loop.ts +0 -50
  150. package/runtime/sdk/g2/scenarios2d.ts +0 -69
  151. package/runtime/sdk/g2/touch.ts +0 -83
  152. package/runtime/sdk/gl/Camera.ts +0 -160
  153. package/runtime/sdk/gl/CameraPlace.ts +0 -52
  154. package/runtime/sdk/gl/CharacterController.ts +0 -238
  155. package/runtime/sdk/gl/Gearbox.ts +0 -212
  156. package/runtime/sdk/gl/Geometry.ts +0 -279
  157. package/runtime/sdk/gl/IK.ts +0 -193
  158. package/runtime/sdk/gl/InstancedMesh.ts +0 -132
  159. package/runtime/sdk/gl/Light.ts +0 -107
  160. package/runtime/sdk/gl/Lightmap.ts +0 -256
  161. package/runtime/sdk/gl/Material.ts +0 -260
  162. package/runtime/sdk/gl/Mesh.ts +0 -83
  163. package/runtime/sdk/gl/Model.ts +0 -124
  164. package/runtime/sdk/gl/NavAgent.ts +0 -337
  165. package/runtime/sdk/gl/NavMesh.ts +0 -397
  166. package/runtime/sdk/gl/Node.ts +0 -350
  167. package/runtime/sdk/gl/Noise.ts +0 -30
  168. package/runtime/sdk/gl/Particles.ts +0 -676
  169. package/runtime/sdk/gl/Physics.ts +0 -222
  170. package/runtime/sdk/gl/Plane.ts +0 -53
  171. package/runtime/sdk/gl/Ragdoll.ts +0 -270
  172. package/runtime/sdk/gl/Ray.ts +0 -16
  173. package/runtime/sdk/gl/Scene.ts +0 -486
  174. package/runtime/sdk/gl/Shape.ts +0 -409
  175. package/runtime/sdk/gl/Terrain.ts +0 -1092
  176. package/runtime/sdk/gl/Texture.ts +0 -63
  177. package/runtime/sdk/gl/Trigger.ts +0 -45
  178. package/runtime/sdk/gl/Vehicle.ts +0 -473
  179. package/runtime/sdk/gl/Wheel.ts +0 -240
  180. package/runtime/sdk/gl/animation/AnimationClip.ts +0 -204
  181. package/runtime/sdk/gl/animation/Animator.ts +0 -120
  182. package/runtime/sdk/gl/animation/Layer.ts +0 -31
  183. package/runtime/sdk/gl/animation/Loop.ts +0 -30
  184. package/runtime/sdk/gl/animation/Playback.ts +0 -44
  185. package/runtime/sdk/gl/animation/core.ts +0 -336
  186. package/runtime/sdk/gl/controls.ts +0 -95
  187. package/runtime/sdk/gl/physicsEvents.ts +0 -20
  188. package/runtime/sdk/gl/scenarios.ts +0 -291
  189. package/runtime/sdk/gl/state.ts +0 -6
  190. package/runtime/sdk/gl/terrainMesh.ts +0 -219
  191. package/runtime/sdk/gl/touch.ts +0 -68
  192. package/runtime/sdk/inject.ts +0 -197
  193. package/runtime/sdk/math/Mathf.ts +0 -118
  194. package/runtime/sdk/math/mat4.ts +0 -278
  195. package/runtime/sdk/math/quat.ts +0 -232
  196. package/runtime/sdk/math/vec.ts +0 -255
  197. package/runtime/sdk/net/codec.ts +0 -119
  198. package/runtime/sdk/net/core.ts +0 -384
  199. package/runtime/sdk/net/index.ts +0 -181
  200. package/runtime/sdk/net/replication.ts +0 -622
  201. package/runtime/sdk/plugins/camera.ts +0 -81
  202. package/runtime/sdk/plugins/geolocation.ts +0 -123
  203. package/runtime/sdk/plugins/oauth.ts +0 -61
  204. package/runtime/sdk/plugins/permission.ts +0 -7
  205. package/runtime/sdk/plugins/push.ts +0 -132
  206. package/runtime/sdk/plugins/qr.ts +0 -73
  207. package/runtime/sdk/plugins/service.ts +0 -47
  208. package/runtime/sdk/runtime/app.ts +0 -101
  209. package/runtime/sdk/runtime/appEvents.ts +0 -54
  210. package/runtime/sdk/runtime/channel.ts +0 -61
  211. package/runtime/sdk/runtime/clipboard.ts +0 -20
  212. package/runtime/sdk/runtime/datetime.ts +0 -329
  213. package/runtime/sdk/runtime/device.ts +0 -293
  214. package/runtime/sdk/runtime/fetch.ts +0 -77
  215. package/runtime/sdk/runtime/files.ts +0 -23
  216. package/runtime/sdk/runtime/input.ts +0 -175
  217. package/runtime/sdk/runtime/media.ts +0 -111
  218. package/runtime/sdk/runtime/misc.ts +0 -16
  219. package/runtime/sdk/runtime/net.ts +0 -36
  220. package/runtime/sdk/runtime/rpc.ts +0 -218
  221. package/runtime/sdk/runtime/service.ts +0 -83
  222. package/runtime/sdk/runtime/share.ts +0 -9
  223. package/runtime/sdk/runtime/storage.ts +0 -13
  224. package/runtime/sdk/runtime/touch.ts +0 -76
  225. package/runtime/sdk/scene/defineScene.ts +0 -1353
  226. package/runtime/sdk/scene/editorPlugins.ts +0 -110
  227. package/runtime/sdk/scene/gizmos.ts +0 -148
  228. package/runtime/sdk/scene/grammar.ts +0 -120
  229. package/runtime/sdk/scene/material.ts +0 -188
  230. package/runtime/sdk/server/auth/appConfig.ts +0 -12
  231. package/runtime/sdk/server/auth/global.ts +0 -80
  232. package/runtime/sdk/server/auth/host.ts +0 -318
  233. package/runtime/sdk/server/auth/models.ts +0 -83
  234. package/runtime/sdk/server/auth/types.ts +0 -50
  235. package/runtime/sdk/server/channel.ts +0 -56
  236. package/runtime/sdk/server/context.ts +0 -36
  237. package/runtime/sdk/server/db/defineDb.ts +0 -237
  238. package/runtime/sdk/server/db/fields.ts +0 -132
  239. package/runtime/sdk/server/db/httpTransport.ts +0 -93
  240. package/runtime/sdk/server/db/index.ts +0 -7
  241. package/runtime/sdk/server/db/marci/query.ts +0 -412
  242. package/runtime/sdk/server/db/types.ts +0 -202
  243. package/runtime/sdk/server/errors.ts +0 -12
  244. package/runtime/sdk/server/host.ts +0 -74
  245. package/runtime/sdk/server/inject.ts +0 -13
  246. package/runtime/sdk/server/runtime.ts +0 -133
  247. package/runtime/sdk/server/validate.ts +0 -87
  248. package/runtime/sdk/ui/NativeView.ts +0 -142
  249. package/runtime/sdk/ui/UI.ts +0 -39
  250. package/runtime/sdk/ui/UIBottomSheet.ts +0 -139
  251. package/runtime/sdk/ui/UIButton.ts +0 -101
  252. package/runtime/sdk/ui/UIContainer.ts +0 -60
  253. package/runtime/sdk/ui/UIImage.ts +0 -83
  254. package/runtime/sdk/ui/UIInput.ts +0 -185
  255. package/runtime/sdk/ui/UIModal.ts +0 -139
  256. package/runtime/sdk/ui/UINode.ts +0 -830
  257. package/runtime/sdk/ui/UIPager.ts +0 -362
  258. package/runtime/sdk/ui/UIPopover.ts +0 -100
  259. package/runtime/sdk/ui/UIScreen.ts +0 -123
  260. package/runtime/sdk/ui/UIScrollable.ts +0 -87
  261. package/runtime/sdk/ui/UISpacer.ts +0 -14
  262. package/runtime/sdk/ui/UITabs.ts +0 -236
  263. package/runtime/sdk/ui/UIText.ts +0 -51
  264. package/runtime/sdk/ui/UIVideo.ts +0 -88
  265. package/runtime/sdk/ui/UIVirtualizedList.ts +0 -241
  266. package/runtime/sdk/ui/UIWidget.ts +0 -127
  267. package/runtime/sdk/ui/fonts.ts +0 -13
  268. package/runtime/sdk/ui/presentable.ts +0 -117
  269. package/runtime/sdk/ui/router.ts +0 -132
  270. package/runtime/sdk/ui/theme.ts +0 -84
@@ -1,222 +0,0 @@
1
- // Rigid body as an aspect on a 3D Node, backed by a JoltPhysics body in creator-gl. Requires a Shape
2
- // aspect on the same node (its geometry becomes the body's collision shape).
3
- //
4
- // Physics.configure({ gravity: [0, -9.81, 0] }) // once, before creating bodies
5
- // ground.aspect(Shape, { box: [20, 0.5, 20] }).aspect(Physics, { motion: 'static' })
6
- // crate.aspect(Shape, {}).aspect(Physics, { mass: 2 }) // auto box from the mesh
7
- // crate.physics.applyImpulse([0, 6, 0])
8
- // crate.addEventListener('enter', other => …) // contact / trigger overlap began
9
- //
10
- // For a `dynamic` body, physics OWNS the transform — do NOT set node.position per frame; drive it via
11
- // velocity / applyImpulse. Reading node.position is free (native already wrote it). A `position` write
12
- // is a TELEPORT that reaches the body (Shape routes it), which is how a kinematic body is placed too.
13
-
14
- import { Aspect } from "../core/Aspect"
15
- import type { FieldMeta } from "../core/fields"
16
- import type { CompAxis, CompWriter } from "../core/compWrite"
17
- import { Vec3, cx, cy, cz, type Vec3Like } from "../math/vec"
18
- import { nodeRegistry, type Node } from "./Node"
19
- import { Shape } from "./Shape"
20
-
21
- export type MotionType = "static" | "dynamic" | "kinematic"
22
- const MOTION: Record<MotionType, number> = { static: 0, kinematic: 1, dynamic: 2 }
23
- // Jolt's angular velocity is rad/s; every angle the SDK exposes is in degrees (like `eulerAngles`).
24
- const DEG2RAD = Math.PI / 180
25
- const RAD2DEG = 180 / Math.PI
26
- // Scratch for velocity reads (one per module, never handed out) — a read allocates the Vec3 only.
27
- const scratch = new Float32Array(3)
28
-
29
- export interface PhysicsConfig {
30
- /** Gravity in world units/s² (Y-up: down is negative). Default [0, -9.81, 0]. */
31
- gravity?: Vec3Like
32
- /** Max simultaneous bodies (resizes the world; only before any body exists). Default 4096. */
33
- maxBodies?: number
34
- }
35
-
36
- /** Closest raycast hit. */
37
- export interface RayHit {
38
- node: Node | null
39
- point: Vec3
40
- normal: Vec3
41
- fraction: number
42
- }
43
-
44
- /**
45
- * What a body's friction already is the moment the host creates it. This is part of the ABI, not an
46
- * assumption: bridges.d.ts states it, so every host owes us this value. Knowing it lets attach skip
47
- * a bridge call per body whenever nobody named a surface.
48
- */
49
- export const DEFAULT_FRICTION = 0.6
50
-
51
- export class Physics extends Aspect<"physics", Node> implements CompWriter {
52
- static readonly aspect = "physics"
53
-
54
- /** Render interpolation of body transforms between the fixed 60 Hz steps (global; default on). Turn
55
- * off to save per-frame transform writes when you have many moving bodies / don't need >60 Hz
56
- * smoothness — bodies then advance in discrete steps. */
57
- private static _interpolation = true
58
- static get interpolation(): boolean { return Physics._interpolation }
59
- static set interpolation(on: boolean) { Physics._interpolation = on; _creator.setInterpolation(on) }
60
-
61
- /** Default "dynamic". */
62
- motion: MotionType = "dynamic"
63
- /** Mass in kg for dynamic bodies (default 1). Ignored for static/kinematic. */
64
- mass = 1
65
- /**
66
- * Surface friction: 0 = ice, ~1 = grippy asphalt, and values above 1 are allowed (rubber on
67
- * tarmac).
68
- *
69
- * The engine COMBINES the two touching bodies as `sqrt(a * b)`, so the LOWER value dominates and
70
- * the floor caps everything standing on it. The default **0.6** is a neutral solid surface (the
71
- * raw Jolt default of 0.2 is ice by game standards); dry tarmac a car should corner on wants a
72
- * `1`, ice `0.02`. A Vehicle's tires read the GROUND body's value, so this is the single number
73
- * that decides how well a car corners.
74
- *
75
- * Change it at runtime by re-configuring — `floor.aspect(Physics, { friction: 0.02 })` (an ice
76
- * patch) — or by assigning `floor.physics.friction = 0.02`; either way the setter pushes the new
77
- * surface to the live body at once. (chisel keeps an instance setter whose name appears as an
78
- * object-literal key anywhere in the bundle, so the config-object route survives tree-shaking
79
- * even when no code reads `.friction`.)
80
- */
81
- get friction(): number { return this._friction }
82
- set friction(v: number) {
83
- this._friction = v
84
- // Unconditional on a live body, unlike attach: it may be on its way BACK to the default from
85
- // something else, and skipping that would leave the ice patch in place.
86
- if (this._bodyId) _creator.physicsSetFriction?.(this._bodyId, v)
87
- }
88
- private _friction = DEFAULT_FRICTION
89
-
90
- /** Scene-editor inspector: `motion` as a dropdown (a string default alone infers a text box). */
91
- static fields: FieldMeta<Physics> = {
92
- motion: { options: [ "static", "kinematic", "dynamic" ] },
93
- mass: { min: 0, step: 0.1 },
94
- friction: { min: 0, max: 2, step: 0.05 },
95
- }
96
-
97
- private _bodyId = 0
98
-
99
- onAttach(): void {
100
- if (!_creator.physicsHasSupport || !_creator.physicsHasSupport()) return
101
- const shape = this.node.get(Shape)
102
- if (!shape) {
103
- throw new Error("Physics requires a Shape aspect — add it first: node.aspect(Shape, {…}).aspect(Physics, {…})")
104
- }
105
- if (this.motion === "dynamic" && shape._isTriangleMesh) {
106
- throw new Error("Physics: a dynamic body cannot use Shape { mesh: true } (triangle meshes are static/kinematic only) — use { mesh: 'convex' } or a primitive shape")
107
- }
108
- const shapeId = shape._claim() // drop the pick-only body; reuse its shape
109
- this._bodyId = _creator.physicsCreateBody(this.node.id, shapeId, MOTION[this.motion], this.mass, false, false)
110
- // A fresh body already carries DEFAULT_FRICTION host-side, so only a NAMED surface has to
111
- // travel — the common case costs no bridge call at all.
112
- if (this._friction !== DEFAULT_FRICTION) _creator.physicsSetFriction?.(this._bodyId, this._friction)
113
- shape._ownBody(this._bodyId)
114
- }
115
-
116
- onDetach(): void {
117
- if (this._bodyId) { _creator.physicsRemoveBody(this._bodyId); this._bodyId = 0 }
118
- const shape = this.node.get(Shape)
119
- if (shape) {
120
- shape._ownBody(0) // the Shape held OUR body id — forget it, or its own detach removes it twice (native crash)
121
- shape._recreatePickBody() // keep the node pickable if the Shape stays
122
- }
123
- }
124
-
125
- /** Native Jolt body id. 0 until attached, or if the build has no physics support. */
126
- get id(): number { return this._bodyId }
127
-
128
- /** Linear velocity in world units/second (fresh Vec3 on read; `velocity.y = 5` written directly on
129
- * the aspect is compiled to a component write — see `_writeComp`). */
130
- get velocity(): Vec3 {
131
- if (!this._bodyId) return new Vec3(0, 0, 0)
132
- _creator.physicsGetLinearVelocity(this._bodyId, scratch)
133
- return new Vec3(scratch[0], scratch[1], scratch[2])
134
- }
135
- set velocity(v: Vec3Like) {
136
- if (this._bodyId) _creator.physicsSetLinearVelocity(this._bodyId, cx(v), cy(v), cz(v))
137
- }
138
-
139
- /**
140
- * Angular velocity — **degrees/second about each world axis** (the SDK's angle unit everywhere;
141
- * the engine works in radians and converts here). Fresh Vec3 on read.
142
- *
143
- * This is the only handle on a body's spin, and placing an object usually needs it: a `position`
144
- * write is a pure teleport, so a crate that was tumbling keeps tumbling at its new home. Putting
145
- * something down is `body.velocity = [0,0,0]; body.angularVelocity = [0,0,0]; node.position = p`.
146
- */
147
- get angularVelocity(): Vec3 {
148
- if (!this._bodyId || !_creator.physicsGetAngularVelocity) return new Vec3(0, 0, 0)
149
- _creator.physicsGetAngularVelocity(this._bodyId, scratch)
150
- return new Vec3(scratch[0] * RAD2DEG, scratch[1] * RAD2DEG, scratch[2] * RAD2DEG)
151
- }
152
- set angularVelocity(v: Vec3Like) {
153
- if (this._bodyId && _creator.physicsSetAngularVelocity) {
154
- _creator.physicsSetAngularVelocity(this._bodyId, cx(v) * DEG2RAD, cy(v) * DEG2RAD, cz(v) * DEG2RAD)
155
- }
156
- }
157
-
158
- /** @internal chisel `comp_write` (see core/compWrite.ts): `body.velocity.y = v` / `body.angularVelocity.z
159
- * = v` written directly on the aspect compile to a call here — one read into the scratch, one set, no
160
- * vector. The list is compile-time data. */
161
- static _comps = [ "velocity", "angularVelocity" ]
162
- _writeComp(prop: string, axis: CompAxis, v: number): void {
163
- if (!this._bodyId || axis === "w") return
164
- const i = axis === "x" ? 0 : axis === "y" ? 1 : 2
165
- if (prop === "velocity") {
166
- _creator.physicsGetLinearVelocity(this._bodyId, scratch)
167
- scratch[i] = v
168
- _creator.physicsSetLinearVelocity(this._bodyId, scratch[0], scratch[1], scratch[2])
169
- } else if (_creator.physicsGetAngularVelocity && _creator.physicsSetAngularVelocity) {
170
- _creator.physicsGetAngularVelocity(this._bodyId, scratch)
171
- scratch[i] = v * DEG2RAD
172
- _creator.physicsSetAngularVelocity(this._bodyId, scratch[0], scratch[1], scratch[2])
173
- }
174
- }
175
-
176
- /** Apply an instantaneous impulse (kg·m/s) and wake the body. */
177
- applyImpulse(v: Vec3Like): this {
178
- if (this._bodyId) _creator.physicsApplyImpulse(this._bodyId, cx(v), cy(v), cz(v))
179
- return this
180
- }
181
-
182
- /** The same impulse applied at a WORLD-SPACE point instead of the centre of mass: the lever arm
183
- * becomes angular impulse, so the body spins as well as moves (a bullet hitting a crate off
184
- * centre, a blast lifting it by its base). Falls back to the central impulse on an older host. */
185
- applyImpulseAt(v: Vec3Like, point: Vec3Like): this {
186
- if (!this._bodyId) return this
187
- if (_creator.physicsApplyImpulseAt) {
188
- _creator.physicsApplyImpulseAt(this._bodyId, cx(v), cy(v), cz(v), cx(point), cy(point), cz(point))
189
- } else {
190
- _creator.physicsApplyImpulse(this._bodyId, cx(v), cy(v), cz(v))
191
- }
192
- return this
193
- }
194
-
195
- // No moveTo(): `node.position = p` IS the move. Shape hands the body id to the node, so a position
196
- // write reaches the body — one way to place anything, whether or not physics is involved.
197
-
198
- // --- world (static) -------------------------------------------------------------------------
199
- /** Configure gravity / limits. Call once before creating bodies. */
200
- static configure(config: PhysicsConfig = {}): void {
201
- const g = config.gravity ?? [0, -9.81, 0]
202
- _creator.physicsConfigure(cx(g), cy(g), cz(g), config.maxBodies ?? 0)
203
- }
204
-
205
- /** Whether this build has physics support (CREATOR_GL_PHYSICS). */
206
- static get supported(): boolean {
207
- return !!_creator.physicsHasSupport && _creator.physicsHasSupport()
208
- }
209
-
210
- /** Closest pickable body hit by the ray from `origin` along `dir` (up to `maxDist`), or null. */
211
- static raycast(origin: Vec3Like, dir: Vec3Like, maxDist = 1000): RayHit | null {
212
- const out = new Float32Array(7)
213
- const id = _creator.physicsRaycast(cx(origin), cy(origin), cz(origin), cx(dir), cy(dir), cz(dir), maxDist, out)
214
- if (!id) return null
215
- return {
216
- node: nodeRegistry.get(id) ?? null,
217
- point: new Vec3(out[0], out[1], out[2]),
218
- normal: new Vec3(out[3], out[4], out[5]),
219
- fraction: out[6],
220
- }
221
- }
222
- }
@@ -1,53 +0,0 @@
1
- // A geometric plane (point + normal) with ray intersection. Ported from worker/src/utils/Plane.ts
2
- // onto the SDK's fluent Vec3 (the mat4 transform() method is omitted — add if needed).
3
-
4
- import { Vec3, type Vec3Like } from "../math/vec"
5
- import type { Ray } from "./Ray"
6
-
7
- export class Plane {
8
- /** Unit normal. */
9
- readonly normal: Vec3
10
- /** Scalar offset: dot(normal, point). */
11
- readonly d: number
12
-
13
- constructor(normal: Vec3Like, point: Vec3Like) {
14
- this.normal = new Vec3(normal).normalize()
15
- this.d = this.normal.dot(point)
16
- }
17
-
18
- static fromPoints(a: Vec3Like, b: Vec3Like, c: Vec3Like): Plane {
19
- const A = new Vec3(a)
20
- return new Plane(new Vec3(b).sub(A).cross(new Vec3(c).sub(A)), a)
21
- }
22
-
23
- static fromCoefficients(a: number, b: number, c: number, d: number): Plane {
24
- const len = Math.hypot(a, b, c)
25
- const l2 = len * len
26
- return new Plane([ a, b, c ], [ (a * d) / l2, (b * d) / l2, (c * d) / l2 ])
27
- }
28
-
29
- /** Ray-plane parameter t (≥0), or null on a miss (parallel / behind origin). */
30
- intersectRay(ray: Ray): number | null {
31
- const denom = this.normal.dot(ray.dir)
32
- if (Math.abs(denom) < 1e-8) return null
33
- const t = (this.d - this.normal.dot(ray.origin)) / denom
34
- return t < 0 ? null : t
35
- }
36
-
37
- /** Like intersectRay but allows hits behind the origin (line-plane). */
38
- intersectLine(ray: Ray): number | null {
39
- const denom = this.normal.dot(ray.dir)
40
- if (Math.abs(denom) < 1e-8) return null
41
- return (this.d - this.normal.dot(ray.origin)) / denom
42
- }
43
-
44
- /** Signed distance from a point (positive on the normal's side). */
45
- signedDistance(point: Vec3Like): number {
46
- return this.normal.dot(point) - this.d
47
- }
48
-
49
- /** Project a point onto the plane. */
50
- projectPoint(point: Vec3Like): Vec3 {
51
- return new Vec3(point).scaleAndAdd(this.normal, -this.signedDistance(point))
52
- }
53
- }
@@ -1,270 +0,0 @@
1
- // A ragdoll: the model's skeleton handed to physics. One rigid body per listed bone — a capsule from
2
- // the bone's origin to the next joint down the chain — joined to its parent part by a swing-twist
3
- // constraint (a cone + a twist range, or a one-way hinge for knees and elbows). Built once at
4
- // attach from the pose the model is in (that pose is the joints' neutral for the limits), and
5
- // switched on and off at will:
6
- //
7
- // const rag = hero.aspect(Ragdoll).get(Ragdoll)! // 'humanoid': the parts by bone name
8
- // rag.activate({ velocity: capsule.controller.velocity }) // drops from its CURRENT pose, keeps its speed
9
- // …
10
- // rag.deactivate() // the animator owns the bones again
11
- //
12
- // While active the engine writes the bodies' poses onto the bones every frame AFTER the animator, so
13
- // the listed bones hide whatever plays underneath; bones NOT listed (fingers, toes, the rest of a
14
- // spine chain between two parts) keep their animated local pose under the ragdolled parents, and
15
- // anything mounted on a bone (a weapon in the hand) rides along. Raycasts hit the parts and report
16
- // the bone node, so a shot knows which limb it struck — `impulse(bone, …)` pushes that part.
17
- //
18
- // The character CONTROLLER is yours to switch off (`node.removeAspect(CharacterController)`): a
19
- // capsule left standing would keep the fallen body from settling. `root` (the hips) tells you where
20
- // the body ended up when it is time to get back up.
21
- //
22
- // A fallen body is scenery, not an obstacle: by default (`collide: 'static'`) only the static world
23
- // and other ragdolls stop it — dynamic bodies, character controllers and vehicles pass through, so it
24
- // never shoves or blocks anything and the solver never pairs it with them — and once every part has
25
- // come to rest (`freeze`, or `freezeAfter` seconds at the latest) the parts turn static where they
26
- // lie: the pose holds, nothing can wake them, the solver skips them. Raycasts hit it either way, and
27
- // a frozen `'all'` body is an obstacle you can stand on.
28
-
29
- import { Aspect } from "../core/Aspect"
30
- import type { FieldMeta } from "../core/fields"
31
- import { cx, cy, cz, type Vec3Like } from "../math/vec"
32
- import { Node } from "./Node"
33
- import { DEFAULT_FRICTION } from "./Physics"
34
-
35
- export interface RagdollHinge {
36
- /** The hinge axis in the MODEL's space (its rest pose: +Z forward, +Y up, +X the model's left in
37
- * glTF). Perpendicular to the bone; the engine drops any component along it. */
38
- axis: Vec3Like
39
- /** The bend range about `axis` in degrees, relative to the pose the ragdoll was built in — a knee
40
- * is `{ axis: [1, 0, 0], min: 0, max: 140 }`: it folds one way only. */
41
- min: number
42
- max: number
43
- }
44
-
45
- export interface RagdollPart {
46
- /** The bone the body sits on — its origin is the joint. */
47
- bone: string
48
- /** The bone the capsule points at (the next joint down). Omitted = a leaf: `length` along the line
49
- * from the parent part's origin (a head, a hand, a foot without toes). */
50
- to?: string
51
- /** The bone of the part this one hangs from (default: the previous part in the list). The root
52
- * has none. */
53
- parent?: string
54
- /** Capsule radius in metres (default 0.05). */
55
- radius?: number
56
- /** Length in metres: a leaf's, or an override of the distance to `to`. */
57
- length?: number
58
- /** This part's share of the ragdoll's `mass` (relative weight, default 1). */
59
- mass?: number
60
- /** Cone half-angle in degrees the part may swing off its parent (default 30). Ignored with `hinge`. */
61
- swing?: number
62
- /** Twist half-angle in degrees about its own axis (default 20). */
63
- twist?: number
64
- /** A one-way joint instead of the cone. */
65
- hinge?: RagdollHinge
66
- }
67
-
68
- const VERSION = 2
69
- const HEADER = 12
70
- const STRIDE = 12
71
-
72
- // Bone names per humanoid role, tried in order: Mixamo / MotusMan / Unity-style first, then UE-style.
73
- // `node.bone()` already matches the part after a `:` / `|` prefix (`mixamorig:Hips`).
74
- const HUMANOID: Record<string, string[]> = {
75
- hips: [ "Hips", "pelvis", "Pelvis", "hip" ],
76
- spine: [ "Spine", "spine_01", "spine", "Spine1" ],
77
- neck: [ "Neck", "neck_01", "neck" ],
78
- head: [ "Head", "head" ],
79
- upperArmL: [ "LeftArm", "upperarm_l", "LeftUpperArm", "UpperArm_L", "L_UpperArm" ],
80
- foreArmL: [ "LeftForeArm", "lowerarm_l", "LeftLowerArm", "LowerArm_L", "L_Forearm" ],
81
- handL: [ "LeftHand", "hand_l", "Hand_L", "L_Hand" ],
82
- upLegL: [ "LeftUpLeg", "thigh_l", "LeftUpperLeg", "UpperLeg_L", "L_Thigh" ],
83
- legL: [ "LeftLeg", "calf_l", "LeftLowerLeg", "LowerLeg_L", "L_Calf" ],
84
- footL: [ "LeftFoot", "foot_l", "Foot_L", "L_Foot" ],
85
- toeL: [ "LeftToeBase", "ball_l", "LeftToe", "Toe_L", "L_Toe" ],
86
- upperArmR: [ "RightArm", "upperarm_r", "RightUpperArm", "UpperArm_R", "R_UpperArm" ],
87
- foreArmR: [ "RightForeArm", "lowerarm_r", "RightLowerArm", "LowerArm_R", "R_Forearm" ],
88
- handR: [ "RightHand", "hand_r", "Hand_R", "R_Hand" ],
89
- upLegR: [ "RightUpLeg", "thigh_r", "RightUpperLeg", "UpperLeg_R", "R_Thigh" ],
90
- legR: [ "RightLeg", "calf_r", "RightLowerLeg", "LowerLeg_R", "R_Calf" ],
91
- footR: [ "RightFoot", "foot_r", "Foot_R", "R_Foot" ],
92
- toeR: [ "RightToeBase", "ball_r", "RightToe", "Toe_R", "R_Toe" ],
93
- }
94
-
95
- /** The standard humanoid layout (hips, one spine capsule up to the neck, head, two-segment arms and
96
- * legs, hands and feet where the rig has them): sizes for a ~1.8 m human, mass shares from body
97
- * segment tables, knees and elbows as hinges that fold the natural way for a model standing in a
98
- * T- or A-pose facing +Z. */
99
- const humanoidParts = (find: (role: string) => string | null): RagdollPart[] => {
100
- const hips = find("hips"), spine = find("spine"), neck = find("neck"), head = find("head")
101
- if (!hips) throw new Error("Ragdoll 'humanoid': no hips bone (Hips / pelvis) on this model — list the parts by name")
102
- const parts: RagdollPart[] = []
103
- parts.push({ bone: hips, to: spine ?? undefined, length: spine ? 0 : 0.2, radius: 0.12, mass: 15 })
104
- const torso = spine ?? hips
105
- if (spine) parts.push({ bone: spine, to: neck ?? head ?? undefined, length: neck || head ? 0 : 0.4, parent: hips, radius: 0.11, mass: 25, swing: 25, twist: 25 })
106
- if (head) parts.push({ bone: head, parent: torso, radius: 0.1, length: 0.2, mass: 6, swing: 35, twist: 45 })
107
- for (const side of [ "L", "R" ] as const) {
108
- const upper = find(`upperArm${side}`), fore = find(`foreArm${side}`), hand = find(`hand${side}`)
109
- if (upper) parts.push({ bone: upper, to: fore ?? undefined, length: fore ? 0 : 0.3, parent: torso, radius: 0.05, mass: 3, swing: 80, twist: 45 })
110
- // the elbow: a T-pose arm along ±X folds its hand forward (+Z) — a negative turn about +Y on the
111
- // left, a positive one on the right
112
- if (upper && fore) parts.push({ bone: fore, to: hand ?? undefined, length: hand ? 0 : 0.28, parent: upper, radius: 0.04, mass: 2, twist: 30, hinge: { axis: [ 0, 1, 0 ], min: side === "L" ? -140 : 0, max: side === "L" ? 0 : 140 } })
113
- if (upper && fore && hand) parts.push({ bone: hand, parent: fore, radius: 0.035, length: 0.16, mass: 1, swing: 30, twist: 20 })
114
- const up = find(`upLeg${side}`), leg = find(`leg${side}`), foot = find(`foot${side}`), toe = find(`toe${side}`)
115
- if (up) parts.push({ bone: up, to: leg ?? undefined, length: leg ? 0 : 0.45, parent: hips, radius: 0.08, mass: 10, swing: 60, twist: 30 })
116
- // the knee: the shin (pointing down) swings its foot backward (−Z) for a positive turn about +X
117
- if (up && leg) parts.push({ bone: leg, to: foot ?? undefined, length: foot ? 0 : 0.42, parent: up, radius: 0.06, mass: 5, twist: 10, hinge: { axis: [ 1, 0, 0 ], min: 0, max: 140 } })
118
- if (up && leg && foot) parts.push({ bone: foot, to: toe ?? undefined, length: toe ? 0 : 0.2, parent: leg, radius: 0.04, mass: 2, swing: 30, twist: 15 })
119
- }
120
- return parts
121
- }
122
-
123
- export class Ragdoll extends Aspect<"ragdoll", Node> {
124
- static readonly aspect = "ragdoll"
125
-
126
- /** The parts: `'humanoid'` (default) finds the standard bones by name; a list places bodies on any
127
- * bones — parents before children. */
128
- parts: RagdollPart[] | "humanoid" = "humanoid"
129
- /** Total mass in kg (default 70), split between the parts by their `mass` shares. */
130
- mass = 70
131
- /** Friction of every part (default 0.6 — the physics default). */
132
- friction = DEFAULT_FRICTION
133
- /** Linear / angular damping of every part; 0 = Jolt's own 0.05. More angular damping settles a
134
- * flailing body sooner. */
135
- linearDamping = 0
136
- angularDamping = 0
137
- /** What the parts collide with. `'static'` (default): the static geometry and other such ragdolls
138
- * only — dynamic bodies, character controllers and vehicles pass through a fallen body, which then
139
- * never shoves or blocks anything and costs nothing when they meet. `'all'`: a regular dynamic
140
- * body that bumps into everything (and gets kicked awake by everything). */
141
- collide: "static" | "all" = "static"
142
- /** Once every part has come to rest the parts turn static where they lie (default true): the pose
143
- * holds, nothing can wake a settled body and it costs the solver nothing — `deactivate()` /
144
- * `activate()` still work (activate makes it dynamic again). */
145
- freeze = true
146
- /** Seconds after `activate()` at which the body freezes whatever it is doing — a twitch on a slope
147
- * or a pile never sleeps on its own. 0 (default) = no cap. */
148
- freezeAfter = 0
149
-
150
- static fields: FieldMeta<Ragdoll> = {
151
- mass: { min: 1, step: 5 },
152
- friction: { min: 0, max: 2, step: 0.05 },
153
- linearDamping: { label: "Linear damping", min: 0, max: 5, step: 0.05 },
154
- angularDamping: { label: "Angular damping", min: 0, max: 5, step: 0.05 },
155
- collide: { options: [ "static", "all" ] },
156
- freezeAfter: { label: "Freeze after (s)", min: 0, max: 60, step: 0.5 },
157
- parts: { hidden: true },
158
- }
159
-
160
- private _id = 0
161
- private _active = false
162
- private _bones: { name: string; node: Node }[] = []
163
-
164
- onAttach(): void {
165
- if (!_creator.physicsHasSupport || !_creator.physicsHasSupport()) return
166
- if (!_creator.ragdollCreate) {
167
- console.warn("Ragdoll needs a newer host (no ragdollCreate) — the body will not fall")
168
- return
169
- }
170
- const find = (role: string): string | null => {
171
- for (const name of HUMANOID[role] ?? []) if (this.node.bone(name)) return name
172
- return null
173
- }
174
- const parts = this.parts === "humanoid" ? humanoidParts(find) : this.parts
175
- if (parts.length === 0) throw new Error("Ragdoll: no parts")
176
-
177
- const n = parts.length
178
- const bones = new Uint32Array(n * 2)
179
- const s = new Float32Array(HEADER + n * STRIDE)
180
- s[0] = VERSION; s[1] = n; s[2] = STRIDE; s[3] = this.friction; s[4] = this.linearDamping; s[5] = this.angularDamping
181
- s[6] = this.collide === "all" ? 0 : 1; s[7] = this.freeze ? 1 : 0; s[8] = Math.max(0, this.freezeAfter)
182
- let shares = 0
183
- for (const p of parts) shares += p.mass ?? 1
184
- this._bones = []
185
- for (let i = 0; i < n; i++) {
186
- const p = parts[i]!
187
- const bone = this.node.bone(p.bone)
188
- if (!bone) throw new Error(`Ragdoll: no bone '${p.bone}' on '${this.node.name}'`)
189
- const to = p.to ? this.node.bone(p.to) : null
190
- if (p.to && !to) throw new Error(`Ragdoll: no bone '${p.to}' (the 'to' of '${p.bone}') on '${this.node.name}'`)
191
- let parent = -1
192
- if (i > 0) {
193
- parent = p.parent ? parts.findIndex((q, j) => j < i && q.bone === p.parent) : i - 1
194
- if (parent < 0) throw new Error(`Ragdoll: the parent '${p.parent}' of '${p.bone}' must be listed before it`)
195
- }
196
- bones[i * 2] = bone.id
197
- bones[i * 2 + 1] = to ? to.id : 0
198
- const o = HEADER + i * STRIDE
199
- s[o] = parent
200
- s[o + 1] = p.radius ?? 0.05
201
- s[o + 2] = p.length ?? 0
202
- s[o + 3] = this.mass * (p.mass ?? 1) / shares
203
- s[o + 4] = p.swing ?? 30
204
- s[o + 5] = p.twist ?? 20
205
- if (p.hinge) {
206
- s[o + 6] = 1
207
- s[o + 7] = cx(p.hinge.axis); s[o + 8] = cy(p.hinge.axis); s[o + 9] = cz(p.hinge.axis)
208
- s[o + 10] = p.hinge.min; s[o + 11] = p.hinge.max
209
- }
210
- this._bones.push({ name: p.bone, node: bone })
211
- }
212
- this._id = _creator.ragdollCreate(this.node.id, bones, s)
213
- if (!this._id) console.warn(`Ragdoll: the host refused the parts on '${this.node.name}'`)
214
- }
215
-
216
- onDetach(): void {
217
- if (this._id) {
218
- if (this._active) _creator.ragdollDeactivate!(this._id)
219
- _creator.ragdollDestroy!(this._id)
220
- this._id = 0
221
- }
222
- this._active = false
223
- this._bones = []
224
- }
225
-
226
- /** Hand the bones to physics from the pose they are in right now. `velocity` (world m/s) is given
227
- * to every part — pass the character's, so a running body keeps travelling. */
228
- activate(opts: { velocity?: Vec3Like } = {}): boolean {
229
- if (!this._id) return false
230
- const v = opts.velocity ?? [ 0, 0, 0 ]
231
- this._active = _creator.ragdollActivate!(this._id, cx(v), cy(v), cz(v))
232
- return this._active
233
- }
234
-
235
- /** Take the bones back: the animator's pose shows again from the next frame. */
236
- deactivate(): void {
237
- if (!this._id || !this._active) return
238
- _creator.ragdollDeactivate!(this._id)
239
- this._active = false
240
- }
241
-
242
- /** Physics owns the bones right now. */
243
- get active(): boolean { return this._active }
244
-
245
- /** Active and every part asleep (or frozen) — the body has come to rest. */
246
- get settled(): boolean {
247
- return this._active && !!this._id && !_creator.ragdollActive!(this._id)
248
- }
249
-
250
- /** The root part's bone (the hips): where the body is. */
251
- get root(): Node | null { return this._bones[0]?.node ?? null }
252
-
253
- /** The bones that carry a part, in order. */
254
- get bones(): string[] { return this._bones.map((b) => b.name) }
255
-
256
- /** The rigid-body id of a part (0 if none) — for the plain body calls. */
257
- bodyOf(bone: string): number {
258
- const i = this._bones.findIndex((b) => b.name === bone)
259
- return i < 0 || !this._id ? 0 : _creator.ragdollBodyId!(this._id, i)
260
- }
261
-
262
- /** Push one part: an impulse in N·s, at a world point (a hit) or through its centre. Wakes the body. */
263
- impulse(bone: string, v: Vec3Like, at?: Vec3Like): boolean {
264
- const id = this.bodyOf(bone)
265
- if (!id) return false
266
- if (at && _creator.physicsApplyImpulseAt) _creator.physicsApplyImpulseAt(id, cx(v), cy(v), cz(v), cx(at), cy(at), cz(at))
267
- else _creator.physicsApplyImpulse(id, cx(v), cy(v), cz(v))
268
- return true
269
- }
270
- }
@@ -1,16 +0,0 @@
1
- // A ray defined by an origin and a (not necessarily normalized) direction.
2
-
3
- import { Vec3, type Vec3Like } from "../math/vec"
4
-
5
- export class Ray {
6
- readonly origin: Vec3
7
- readonly dir: Vec3
8
-
9
- constructor(origin: Vec3Like, dir: Vec3Like) {
10
- this.origin = new Vec3(origin)
11
- this.dir = new Vec3(dir)
12
- }
13
-
14
- /** The world-space point origin + t·dir. */
15
- getPoint(t: number): Vec3 { return this.origin.scaleAndAdd(this.dir, t) }
16
- }