vmGeom
<!-- zero:scaffolded-readme --> <!-- Replace the line below with what this module provides and who consumes it, then delete both comment lines. -->
vmGeom
<!-- zero:scaffolded-readme --> <!-- Replace the line below with what this module provides and who consumes it, then delete both comment lines. -->TODO: describe this module.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
conforms to
zero/source-extract/v2CHAFF — the viewmodel geometry kit. Slice B builds its hands, its weapon and its visor out of lofted solids rather than scaled cubes: a loft is a stack of closed cross-sections along an axis, and one superellipse exponent takes that section from a circle (n = 2) through a chamfered rectangle (n = 5) to a hard box (n = 12). A finger, a barrel, a receiver and a grip are all the same call with a different profile, which is what makes a hand-built viewmodel affordable. Everything here is a pure function of numbers and returns a MeshGeometry — flat `positions` / `indices` / `normals` / `uvs` arrays, the shape `asset.create("mesh", ...)` and `renderer.mesh.create` both take. Axes are the engine's: +X right, +Y up, and -Z the direction an entity's transform.forward points. Parts that point out of the screen are lofted along -Z so their local forward already agrees with the entity's.
sgn(x: number) → number
| arg | type | description |
|---|---|---|
| x | number |
section(theta: number, n: number) → void
One point on a superellipse of exponent `n`, at angle `theta`. n = 2 is a circle; n grows toward a rectangle with rounded corners.
| arg | type | description |
|---|---|---|
| theta | number | |
| n | number |
loft(rings: { any }, opts: any?) → any
`rings` is an ordered list of cross-sections along the axis: { t = <position along the axis>, a = <half-extent on the first cross axis>, b = <half-extent on the second>, n = <exponent>, ca, cb = <offset of the section's centre> } opts: { seg, axis = "x" | "y" | "z", capStart, capEnd, uvScale } The cross axes are the two the axis is not, in x → y → z → x order: for axis "y" the section lies in (x, z); for "z" it lies in (x, y).
| arg | type | description |
|---|---|---|
| rings | { any } | |
| opts | any? |
put(t: number, u: number, v: number) → void
| arg | type | description |
|---|---|---|
| t | number | |
| u | number | |
| v | number |
cap(ringIndex: number, base: number) → void
| arg | type | description |
|---|---|---|
| ringIndex | number | |
| base | number |
recomputeNormals(g: any) → void
Accumulate face normals into their vertices and normalise. Smooth by construction: a loft's chamfers are what carry the highlight, so a hard crease is authored as a tight pair of rings rather than as split vertices.
| arg | type | description |
|---|---|---|
| g | any |
orientOutward(g: any) → void
Every solid here is convex enough that "outward" means "away from the centroid". If the mesh came out inside-out, reverse every triangle and the normals with them, so a back-face-culling material draws the side that is actually facing the camera.
| arg | type | description |
|---|---|---|
| g | any |
tube(t0: number, t1: number, steps: number, shape: (number) → void
A tube along `axis` from `t0` to `t1`, whose section is read from `shape` at each step: shape(v) -> a, b, n, ca, cb (v goes 0 → 1 along the run). `round0` / `round1` add a hemispherical dome of that many extra rings on each end instead of a flat cap.
| arg | type | description |
|---|---|---|
| t0 | number | |
| t1 | number | |
| steps | number | |
| shape | (number |
ringAt(v: number, scale: number, tOverride: number?) → void
| arg | type | description |
|---|---|---|
| v | number | |
| scale | number | |
| tOverride | number? |
limb(len: number, r0: number, r1: number, opts: any?) → any
A capsule-ish limb segment: length `len` along `axis`, radius `r0` at the root tapering to `r1` at the tip, flattened by `flat` on the second cross axis. This is a finger bone, a forearm, a grip and a barrel.
| arg | type | description |
|---|---|---|
| len | number | |
| r0 | number | |
| r1 | number | |
| opts | any? |
box(w: number, h: number, d: number, opts: any?) → any
A chamfered box centred on its own origin. `n` sets how hard the edges are.
| arg | type | description |
|---|---|---|
| w | number | |
| h | number | |
| d | number | |
| opts | any? |
quad(w: number, h: number) → any
A flat quad in XY, facing +Z. The visor tint and the muzzle bloom are drawn on these.
| arg | type | description |
|---|---|---|
| w | number | |
| h | number |
annulus(rInner: number, rOuter: number, thick: number, opts: any?) → any
A flat annulus in the plane normal to `axis` — the wrist coupling, the muzzle collar, the drum magazine's rim.
| arg | type | description |
|---|---|---|
| rInner | number | |
| rOuter | number | |
| thick | number | |
| opts | any? |
eulerMatrix(ex: number, ey: number, ez: number) → void
Several lofts welded into ONE mesh: the receiver, its rail, its ejection port and its trigger guard are one asset and one draw, not four entities an animation has to keep in step.
| arg | type | description |
|---|---|---|
| ex | number | |
| ey | number | |
| ez | number |
xform(g: any, spec: any?) → any
| arg | type | description |
|---|---|---|
| g | any | |
| spec | any? |
merge(parts: { any }) → any
| arg | type | description |
|---|---|---|
| parts | { any } |
stats(g: any) → any
| arg | type | description |
|---|---|---|
| g | any |
Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
agent_score is exposed.+ quality × 0.35
+ performance × 0.25
± compat factor
Usability ratings
Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".
Scoped to this part · feeds back into the world's score.