@developerz.ai/ts23d 0.1.0 → 0.2.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 (162) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/CLAUDE.md +1 -1
  3. package/README.md +10 -5
  4. package/dist/{chunk-a8fxakcj.js → chunk-6b05mnmx.js} +2 -2
  5. package/dist/{chunk-kgvbpqqw.js → chunk-7rtfjh9f.js} +6 -5
  6. package/dist/chunk-7rtfjh9f.js.map +10 -0
  7. package/dist/{chunk-1ypfs7ga.js → chunk-8j4c28jt.js} +790 -276
  8. package/dist/chunk-8j4c28jt.js.map +46 -0
  9. package/dist/{chunk-wtqhq529.js → chunk-d1fv6hrm.js} +6 -6
  10. package/dist/{chunk-wtqhq529.js.map → chunk-d1fv6hrm.js.map} +1 -1
  11. package/dist/{chunk-gcyp9b4d.js → chunk-dbq4qf52.js} +362 -215
  12. package/dist/chunk-dbq4qf52.js.map +25 -0
  13. package/dist/{chunk-xnt2sdhf.js → chunk-drna2rny.js} +2 -2
  14. package/dist/{chunk-ravbb06q.js → chunk-dxvypr7y.js} +2 -2
  15. package/dist/{chunk-11v28977.js → chunk-f6yme003.js} +85 -71
  16. package/dist/{chunk-11v28977.js.map → chunk-f6yme003.js.map} +6 -6
  17. package/dist/{chunk-4ddzsqtc.js → chunk-hg7pf34j.js} +4 -3
  18. package/dist/{chunk-4ddzsqtc.js.map → chunk-hg7pf34j.js.map} +5 -5
  19. package/dist/{chunk-w1zyhj40.js → chunk-jq4e17tj.js} +2 -2
  20. package/dist/{chunk-kvcep7ft.js → chunk-y63c6zcv.js} +967 -218
  21. package/dist/chunk-y63c6zcv.js.map +53 -0
  22. package/dist/cli/args.d.ts +7 -1
  23. package/dist/cli/bin.js +66 -25
  24. package/dist/cli/bin.js.map +6 -5
  25. package/dist/cli/manifest.d.ts +5 -1
  26. package/dist/cli/texture-cache.d.ts +4 -0
  27. package/dist/core/definition.d.ts +7 -0
  28. package/dist/core/errors.d.ts +1 -1
  29. package/dist/core/index.js +1 -1
  30. package/dist/export/credits.d.ts +4 -0
  31. package/dist/export/glb-options.d.ts +48 -0
  32. package/dist/export/glb.d.ts +5 -35
  33. package/dist/export/hierarchy.d.ts +23 -0
  34. package/dist/export/index.d.ts +2 -1
  35. package/dist/export/index.js +21 -7
  36. package/dist/export/index.js.map +1 -1
  37. package/dist/export/lod-coverage.d.ts +12 -0
  38. package/dist/export/metadata.d.ts +2 -0
  39. package/dist/export/version.d.ts +2 -2
  40. package/dist/grammar/index.js +2 -2
  41. package/dist/index.js +63 -17
  42. package/dist/index.js.map +1 -1
  43. package/dist/kinds/head-armour.d.ts +3 -7
  44. package/dist/kinds/head-bust.d.ts +3 -2
  45. package/dist/kinds/head-face.d.ts +3 -1
  46. package/dist/kinds/head-garb.d.ts +4 -0
  47. package/dist/kinds/head-mesh.d.ts +4 -0
  48. package/dist/kinds/head-mouth.d.ts +4 -0
  49. package/dist/kinds/head-params.d.ts +9 -1
  50. package/dist/kinds/head-tone.d.ts +10 -0
  51. package/dist/kinds/head-torso.d.ts +35 -0
  52. package/dist/kinds/index.js +6 -6
  53. package/dist/material/cc0.d.ts +4 -0
  54. package/dist/material/define.d.ts +34 -0
  55. package/dist/material/generator.d.ts +1 -1
  56. package/dist/material/index.d.ts +8 -3
  57. package/dist/material/index.js +39 -7
  58. package/dist/material/index.js.map +1 -1
  59. package/dist/material/library.d.ts +7 -0
  60. package/dist/material/material-def.d.ts +30 -0
  61. package/dist/material/paint/canvas.d.ts +7 -0
  62. package/dist/material/paint/default-sheet.d.ts +3 -1
  63. package/dist/material/paint/fabric.d.ts +4 -0
  64. package/dist/material/paint/image-strip.d.ts +4 -0
  65. package/dist/material/paint/kit.d.ts +5 -0
  66. package/dist/material/paint/metal.d.ts +3 -0
  67. package/dist/material/paint/orm.d.ts +1 -1
  68. package/dist/material/paint/strip.d.ts +1 -1
  69. package/dist/material/paint/types.d.ts +32 -2
  70. package/dist/material/palette.d.ts +2 -0
  71. package/dist/material/slots.d.ts +5 -0
  72. package/dist/material/texture-source.d.ts +34 -0
  73. package/dist/material/trim-sheet.d.ts +20 -4
  74. package/dist/neural/index.js +2 -2
  75. package/dist/passes/index.js +2 -2
  76. package/dist/primitives/index.js +3 -3
  77. package/dist/qa/index.js +2 -2
  78. package/dist/render/beauty.d.ts +1 -1
  79. package/dist/render/index.js +3 -3
  80. package/dist/render/lighting.d.ts +7 -0
  81. package/dist/render/shade.d.ts +1 -1
  82. package/dist/testing/index.js +5 -5
  83. package/docs/README.md +4 -0
  84. package/docs/architecture/gltf-capabilities.md +38 -1
  85. package/docs/architecture/materials.md +151 -0
  86. package/docs/idea/10-sculpting.md +166 -0
  87. package/docs/idea/11-materials-authoring.md +132 -0
  88. package/docs/idea/12-blender-bridge.md +136 -0
  89. package/docs/idea/13-asset-pipeline-research.md +89 -0
  90. package/docs/plans/roadmap.md +12 -0
  91. package/package.json +2 -1
  92. package/recipes/boxcar/README.md +7 -0
  93. package/recipes/boxcar/boxcar.ts +118 -34
  94. package/recipes/goblin_head/README.md +27 -14
  95. package/recipes/goblin_head/goblin_head.ts +11 -9
  96. package/recipes/human_head/README.md +8 -4
  97. package/recipes/human_head/human_head.ts +4 -3
  98. package/recipes/material_swatches/material_swatches.ts +11 -5
  99. package/recipes/orc_head/README.md +32 -20
  100. package/recipes/orc_head/orc_head.ts +9 -7
  101. package/src/cli/args.ts +16 -3
  102. package/src/cli/manifest.ts +6 -0
  103. package/src/cli/run.ts +33 -9
  104. package/src/cli/texture-cache.ts +24 -0
  105. package/src/core/asset.ts +1 -0
  106. package/src/core/definition.ts +7 -0
  107. package/src/core/errors.ts +6 -1
  108. package/src/export/credits.ts +25 -0
  109. package/src/export/glb-options.ts +53 -0
  110. package/src/export/glb.ts +100 -113
  111. package/src/export/hierarchy.ts +122 -0
  112. package/src/export/index.ts +17 -1
  113. package/src/export/lod-coverage.ts +71 -0
  114. package/src/export/metadata.ts +3 -0
  115. package/src/export/version.ts +1 -1
  116. package/src/kinds/head-armour.ts +103 -73
  117. package/src/kinds/head-bust.ts +49 -86
  118. package/src/kinds/head-face.ts +94 -74
  119. package/src/kinds/head-garb.ts +181 -0
  120. package/src/kinds/head-hair.ts +74 -33
  121. package/src/kinds/head-mesh.ts +43 -5
  122. package/src/kinds/head-mouth.ts +111 -0
  123. package/src/kinds/head-params.ts +11 -2
  124. package/src/kinds/head-presets.ts +30 -27
  125. package/src/kinds/head-tone.ts +52 -0
  126. package/src/kinds/head-torso.ts +230 -0
  127. package/src/kinds/head.ts +8 -3
  128. package/src/material/cc0.ts +41 -0
  129. package/src/material/define.ts +130 -0
  130. package/src/material/generator.ts +15 -8
  131. package/src/material/index.ts +34 -3
  132. package/src/material/library.ts +196 -0
  133. package/src/material/material-def.ts +84 -0
  134. package/src/material/paint/canvas.ts +11 -1
  135. package/src/material/paint/compose.ts +1 -1
  136. package/src/material/paint/decode-png.ts +19 -13
  137. package/src/material/paint/default-sheet.ts +40 -28
  138. package/src/material/paint/fabric.ts +63 -0
  139. package/src/material/paint/image-strip.ts +88 -0
  140. package/src/material/paint/kit.ts +37 -0
  141. package/src/material/paint/masks.ts +3 -1
  142. package/src/material/paint/metal.ts +109 -0
  143. package/src/material/paint/orm.ts +14 -1
  144. package/src/material/paint/planks.ts +49 -4
  145. package/src/material/paint/strip.ts +35 -29
  146. package/src/material/paint/types.ts +45 -2
  147. package/src/material/paint/validate.ts +19 -3
  148. package/src/material/palette.ts +3 -0
  149. package/src/material/slots.ts +18 -0
  150. package/src/material/texture-source.ts +86 -0
  151. package/src/material/trim-sheet.ts +79 -13
  152. package/src/render/beauty.ts +2 -2
  153. package/src/render/lighting.ts +26 -0
  154. package/src/render/shade.ts +10 -5
  155. package/dist/chunk-1ypfs7ga.js.map +0 -42
  156. package/dist/chunk-gcyp9b4d.js.map +0 -22
  157. package/dist/chunk-kgvbpqqw.js.map +0 -10
  158. package/dist/chunk-kvcep7ft.js.map +0 -43
  159. /package/dist/{chunk-a8fxakcj.js.map → chunk-6b05mnmx.js.map} +0 -0
  160. /package/dist/{chunk-xnt2sdhf.js.map → chunk-drna2rny.js.map} +0 -0
  161. /package/dist/{chunk-ravbb06q.js.map → chunk-dxvypr7y.js.map} +0 -0
  162. /package/dist/{chunk-w1zyhj40.js.map → chunk-jq4e17tj.js.map} +0 -0
@@ -1,22 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/export/bin-writer.ts", "../src/export/container.ts", "../src/export/lights.ts", "../src/export/materials.ts", "../src/export/merge-pivots.ts", "../src/export/version.ts", "../src/export/metadata.ts", "../src/export/motion.ts", "../src/export/optimize-parts.ts", "../src/export/tangents.ts", "../src/export/primitive.ts", "../src/export/textures.ts", "../src/export/glb.ts"],
4
- "sourcesContent": [
5
- "// Packs typed arrays into one 4-byte-aligned glTF buffer and records bufferViews + accessors.\n\nexport const ARRAY_BUFFER = 34962;\nexport const ELEMENT_ARRAY_BUFFER = 34963;\nconst FLOAT = 5126;\nconst UINT32 = 5125;\nconst UINT16 = 5123;\n\nexport interface Json {\n [key: string]: unknown;\n}\n\nexport class BinWriter {\n private readonly chunks: Uint8Array[] = [];\n length = 0;\n readonly views: Json[] = [];\n readonly accessors: Json[] = [];\n\n private push(bytes: Uint8Array, target?: number): number {\n const pad = (4 - (this.length % 4)) % 4;\n if (pad) {\n this.chunks.push(new Uint8Array(pad));\n this.length += pad;\n }\n this.views.push({\n buffer: 0,\n byteOffset: this.length,\n byteLength: bytes.byteLength,\n ...(target ? { target } : {}),\n });\n this.chunks.push(bytes);\n this.length += bytes.byteLength;\n return this.views.length - 1;\n }\n\n accessor(\n data: Float32Array | Uint32Array | Uint16Array,\n type: 'SCALAR' | 'VEC2' | 'VEC3' | 'VEC4',\n target?: number,\n bounds = false,\n /** Integer data read as 0..1 (vertex colour as normalised unsigned short). */\n normalized = false,\n ): number {\n const view = this.push(new Uint8Array(data.buffer, data.byteOffset, data.byteLength), target);\n const width = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4 }[type];\n const acc: Json = {\n bufferView: view,\n componentType:\n data instanceof Uint32Array ? UINT32 : data instanceof Uint16Array ? UINT16 : FLOAT,\n count: data.length / width,\n type,\n ...(normalized ? { normalized: true } : {}),\n };\n if (bounds) {\n const min = Array<number>(width).fill(Infinity);\n const max = Array<number>(width).fill(-Infinity);\n for (let i = 0; i < data.length; i++) {\n const k = i % width;\n const v = data[i] ?? 0;\n if (v < (min[k] ?? 0)) min[k] = v;\n if (v > (max[k] ?? 0)) max[k] = v;\n }\n acc['min'] = min;\n acc['max'] = max;\n }\n this.accessors.push(acc);\n return this.accessors.length - 1;\n }\n\n bytes(): Uint8Array {\n const out = new Uint8Array(Math.ceil(this.length / 4) * 4);\n let o = 0;\n for (const c of this.chunks) {\n out.set(c, o);\n o += c.byteLength;\n }\n return out;\n }\n}\n",
6
- "// The GLB container: 12-byte header, JSON chunk (space-padded), BIN chunk (zero-padded), every\n// length a multiple of 4 [glTF 2.0 §glb-file-format-specification].\n\nimport type { Json } from './bin-writer.ts';\n\nexport function packGlb(gltf: Json, body: Uint8Array): Uint8Array {\n let json = new TextEncoder().encode(JSON.stringify(gltf));\n const jsonPad = (4 - (json.byteLength % 4)) % 4;\n if (jsonPad) {\n const padded = new Uint8Array(json.byteLength + jsonPad).fill(0x20);\n padded.set(json);\n json = padded;\n }\n const total = 12 + 8 + json.byteLength + 8 + body.byteLength;\n const out = new Uint8Array(total);\n const dv = new DataView(out.buffer);\n dv.setUint32(0, 0x46546c67, true);\n dv.setUint32(4, 2, true);\n dv.setUint32(8, total, true);\n dv.setUint32(12, json.byteLength, true);\n dv.setUint32(16, 0x4e4f534a, true);\n out.set(json, 20);\n const binAt = 20 + json.byteLength;\n dv.setUint32(binAt, body.byteLength, true);\n dv.setUint32(binAt + 4, 0x004e4942, true);\n out.set(body, binAt + 8);\n return out;\n}\n\nexport function concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.byteLength + b.byteLength);\n out.set(a);\n out.set(b, a.byteLength);\n return out;\n}\n",
7
- "// KHR_lights_punctual from light sockets: `ctx.socket('headlamp_l', { kind: 'light', dir,\n// data: { light: 'spot', color: '#ffe8c0', intensity: 200, range: 30, cone: 25 } })` becomes a\n// real light every engine and viewer can switch on. The socket node stays as authored; the light\n// rides a child node `<socket>_light` rotated so its −Z (the glTF light direction) is `dir`.\n\nimport type { Part, Quat, Vec3 } from '../core/index.ts';\nimport { hex } from '../material/index.ts';\nimport type { Json } from './bin-writer.ts';\n\nexport const LIGHTS = 'KHR_lights_punctual';\n\n/** Shortest rotation taking unit `a` onto unit `b`. */\nfunction between(a: Vec3, b: Vec3): Quat {\n const d = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n if (d < -0.999999) return [1, 0, 0, 0]; // opposite: half turn about X (⊥ to −Z)\n const c: Vec3 = [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];\n const w = 1 + d;\n const n = Math.hypot(c[0], c[1], c[2], w);\n return [c[0] / n, c[1] / n, c[2] / n, w / n];\n}\n\nconst num = (v: unknown, fallback: number): number =>\n typeof v === 'number' && Number.isFinite(v) ? v : fallback;\n\n/** The glTF light for a light socket, or null for any other part. */\nexport function lightOf(part: Part): { light: Json; rotation: Quat } | null {\n const s = part.socket;\n if (s?.kind !== 'light') return null;\n const d = s.data ?? {};\n const type = d['light'] === 'point' || d['light'] === 'directional' ? d['light'] : 'spot';\n const color = typeof d['color'] === 'string' ? hex(d['color']) : [1, 1, 1];\n const dir = s.dir ?? [1, 0, 0];\n const len = Math.hypot(...dir) || 1;\n const outer = (Math.min(89, num(d['cone'], 30)) * Math.PI) / 180;\n const inner = Math.min(outer * 0.999, (num(d['inner'], 0) * Math.PI) / 180);\n const range = num(d['range'], 0);\n return {\n light: {\n name: part.name,\n type,\n color,\n // Spot/point: candela; directional: lux. Defaults suit a vehicle lamp / a sun.\n intensity: num(d['intensity'], type === 'directional' ? 3 : type === 'point' ? 20 : 100),\n ...(range > 0 && type !== 'directional' ? { range } : {}),\n ...(type === 'spot' ? { spot: { innerConeAngle: inner, outerConeAngle: outer } } : {}),\n },\n rotation: between([0, 0, -1], [dir[0] / len, dir[1] / len, dir[2] / len]),\n };\n}\n",
8
- "// The (at most) four shared materials, one per Surface in use. All sample the same trim sheet and\n// take tint from COLOR_0, so batching holds; only the shading model differs. Glass/translucent use\n// KHR_materials_transmission + _volume + _ior (three, Babylon, glTFast); engines without them fall\n// back to alpha BLEND via baseColorFactor.a. With a painted sheet bound (textures.ts), every\n// material samples it: baseColor (sRGB, alpha = cutout mask), normal, and ORM in both the\n// occlusion and metallicRoughness slots. Opaque/cutout factors go to 1 so the ORM texture rules;\n// glass/translucent keep theirs as multipliers (clear stays clear whatever strip it maps).\n\nimport type { Surface } from '../core/index.ts';\nimport type { Json } from './bin-writer.ts';\n\nconst MATERIALS: Readonly<Record<Surface, Json>> = {\n opaque: {\n name: 'ts23d_trim',\n pbrMetallicRoughness: {\n baseColorFactor: [1, 1, 1, 1],\n metallicFactor: 0,\n roughnessFactor: 0.8,\n },\n },\n cutout: {\n name: 'ts23d_trim_cutout',\n alphaMode: 'MASK',\n alphaCutoff: 0.5,\n doubleSided: true,\n pbrMetallicRoughness: {\n baseColorFactor: [1, 1, 1, 1],\n metallicFactor: 0,\n roughnessFactor: 0.9,\n },\n },\n glass: {\n name: 'ts23d_glass',\n alphaMode: 'BLEND',\n pbrMetallicRoughness: {\n baseColorFactor: [1, 1, 1, 0.25],\n metallicFactor: 0,\n roughnessFactor: 0.05,\n },\n extensions: {\n KHR_materials_transmission: { transmissionFactor: 1 },\n KHR_materials_volume: { thicknessFactor: 0.01 },\n KHR_materials_ior: { ior: 1.5 },\n },\n },\n translucent: {\n name: 'ts23d_translucent',\n alphaMode: 'BLEND',\n pbrMetallicRoughness: {\n baseColorFactor: [1, 1, 1, 0.6],\n metallicFactor: 0,\n roughnessFactor: 0.35,\n },\n extensions: {\n KHR_materials_transmission: { transmissionFactor: 0.6 },\n KHR_materials_volume: { thicknessFactor: 0.02 },\n KHR_materials_ior: { ior: 1.45 },\n },\n },\n};\n\nconst ORDER: readonly Surface[] = ['opaque', 'cutout', 'glass', 'translucent'];\n\n/** The same material sampling the sheet (texture indices fixed by textures.ts). */\nfunction textured(m: Json, surface: Surface): Json {\n const pbr = m['pbrMetallicRoughness'] as Json;\n const own = surface === 'opaque' || surface === 'cutout';\n return {\n ...m,\n pbrMetallicRoughness: {\n ...pbr,\n baseColorTexture: { index: 0 },\n metallicRoughnessTexture: { index: 2 },\n ...(own ? { metallicFactor: 1, roughnessFactor: 1 } : {}),\n },\n normalTexture: { index: 1 },\n occlusionTexture: { index: 2 },\n };\n}\n\n/** Materials for the surfaces present, plus each surface's index and the extensions used. */\nexport function materialsFor(\n used: ReadonlySet<Surface>,\n withSheet = false,\n): {\n materials: Json[];\n index: Map<Surface, number>;\n extensionsUsed: string[];\n} {\n const present = ORDER.filter((s) => s === 'opaque' || used.has(s));\n const index = new Map(present.map((s, i) => [s, i] as const));\n const ext = new Set<string>();\n for (const s of present)\n for (const e of Object.keys((MATERIALS[s]['extensions'] as Json | undefined) ?? {})) ext.add(e);\n const materials = present.map((s) => (withSheet ? textured(MATERIALS[s], s) : MATERIALS[s]));\n return { materials, index, extensionsUsed: [...ext].sort() };\n}\n\nexport const EMISSIVE_STRENGTH = 'KHR_materials_emissive_strength';\n\n/** A lit surface: lamp lenses, windows at night, panel glow. */\nexport interface GlowRule {\n /** Part names or globs: 'headlamp_*', 'window_*'. */\n readonly parts: readonly string[];\n /** Linear RGB 0..1 (use `hex('#ffd9a0')` from /material). Default warm white. */\n readonly color?: readonly [number, number, number];\n /** Brightness multiplier (KHR_materials_emissive_strength, Ratified); 1 = plain glTF. */\n readonly strength?: number;\n}\n\n/**\n * The opaque trim material plus emission. emissiveFactor caps at 1 in core glTF; anything\n * brighter rides KHR_materials_emissive_strength (engines without it see the clamped glow).\n */\nexport function glowMaterial(rule: GlowRule, i: number, withSheet: boolean): Json {\n const base = withSheet ? textured(MATERIALS.opaque, 'opaque') : MATERIALS.opaque;\n const strength = rule.strength ?? 4;\n return {\n ...base,\n name: `ts23d_glow_${i}`,\n emissiveFactor: [...(rule.color ?? [1, 0.85, 0.6])],\n ...(strength !== 1\n ? { extensions: { [EMISSIVE_STRENGTH]: { emissiveStrength: strength } } }\n : {}),\n };\n}\n",
9
- "// Batching for engines: every part that is NOT a pivot is merged into its nearest pivot ancestor,\n// so draw calls = pivots with geometry, not parts. A pivot is anything the engine may move: a\n// group (`ctx.group`, a named handle like `turret`, `gun`, `door_l`) or a part with `motion`.\n// Static top-level geometry merges into one `body` part. Names the engine binds to survive.\n// Non-opaque surfaces split into `<pivot>_<surface>` children (one draw call per surface), and\n// glowing parts (GlbOptions.glow) into `<pivot>_glow_<i>` children with their emissive material.\n\nimport {\n type CompiledAsset,\n type Mesh,\n merge,\n type Part,\n rotateZ,\n type Surface,\n toWorld,\n type WorldTransform,\n worldTransforms,\n} from '../core/index.ts';\n\nconst isPivot = (p: Part): boolean => p.mesh === null || p.motion !== null;\n\n/** Merged layer parts that glow → index of the glow rule (read by the GLB writer). */\nexport const glowLayer = new WeakMap<Part, number>();\n\n/** `*`/`?` glob → anchored RegExp (export cannot import /qa: same tier). */\nexport const globRe = (pattern: string): RegExp =>\n new RegExp(\n `^${pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replaceAll('*', '.*')\n .replaceAll('?', '.')}$`,\n );\nconst SURFACES: readonly Surface[] = ['cutout', 'glass', 'translucent'];\n\n/** Re-express a part's mesh in its pivot's local space. */\nfunction intoPivot(mesh: Mesh, part: WorldTransform, pivot: WorldTransform): Mesh {\n const positions = new Float32Array(mesh.positions.length);\n const normals = new Float32Array(mesh.normals.length);\n for (let i = 0; i < positions.length; i += 3) {\n const w = toWorld(part, [\n mesh.positions[i] ?? 0,\n mesh.positions[i + 1] ?? 0,\n mesh.positions[i + 2] ?? 0,\n ]);\n positions.set(\n rotateZ([w[0] - pivot.origin[0], w[1] - pivot.origin[1], w[2] - pivot.origin[2]], -pivot.yaw),\n i,\n );\n normals.set(\n rotateZ(\n rotateZ(\n [mesh.normals[i] ?? 0, mesh.normals[i + 1] ?? 0, mesh.normals[i + 2] ?? 0],\n part.yaw,\n ),\n -pivot.yaw,\n ),\n i,\n );\n }\n return { ...mesh, positions, normals };\n}\n\nexport function mergeToPivots(\n asset: CompiledAsset,\n glow: readonly (readonly string[])[] = [],\n): CompiledAsset {\n const glowRes = glow.map((globs) => globs.map(globRe));\n const glowOf = (name: string): number => glowRes.findIndex((rs) => rs.some((r) => r.test(name)));\n const byName = new Map(asset.parts.map((p) => [p.name, p]));\n const xf = worldTransforms(asset.parts);\n const ROOT = 'body';\n const identity: WorldTransform = { origin: [0, 0, 0], yaw: 0 };\n const pivotOf = (p: Part): string => {\n let cur = p.parent ? byName.get(p.parent) : undefined;\n while (cur && !isPivot(cur)) cur = cur.parent ? byName.get(cur.parent) : undefined;\n return cur?.name ?? ROOT;\n };\n // Buckets keyed by pivot + surface: opaque merges into the pivot's own mesh; each other\n // surface in use becomes one child `<pivot>_<surface>` so materials never mix in a primitive.\n const extra = new Map<string, Mesh[]>();\n const bucket = (pivot: string, surface: Surface | undefined, mesh: Mesh, g = -1): void => {\n const k = `${pivot}|${g >= 0 ? `glow_${g}` : (surface ?? 'opaque')}`;\n extra.set(k, [...(extra.get(k) ?? []), mesh]);\n };\n for (const p of asset.parts) {\n if (!p.mesh) continue;\n const g = glowOf(p.name);\n if (isPivot(p)) {\n bucket(p.name, p.surface, p.mesh, g);\n continue;\n }\n const pivot = pivotOf(p);\n const t = xf.get(p.name) ?? identity;\n const pt = pivot === ROOT ? identity : (xf.get(pivot) ?? identity);\n bucket(pivot, p.surface, intoPivot(p.mesh, t, pt), g);\n }\n const parts: Part[] = [];\n const layers = (pivot: string, parent: string | null): void => {\n for (const surface of SURFACES) {\n const meshes = extra.get(`${pivot}|${surface}`);\n if (!meshes) continue;\n parts.push({\n name: `${pivot}_${surface}`,\n mesh: merge(meshes),\n at: [0, 0, 0],\n parent,\n yaw: 0,\n motion: null,\n surface,\n });\n }\n glow.forEach((_, g) => {\n const meshes = extra.get(`${pivot}|glow_${g}`);\n if (!meshes) return;\n const part: Part = {\n name: `${pivot}_glow_${g}`,\n mesh: merge(meshes),\n at: [0, 0, 0],\n parent,\n yaw: 0,\n motion: null,\n };\n glowLayer.set(part, g);\n parts.push(part);\n });\n };\n const body = extra.get(`${ROOT}|opaque`);\n if (body)\n parts.push({\n name: ROOT,\n mesh: merge(body),\n at: [0, 0, 0],\n parent: null,\n yaw: 0,\n motion: null,\n });\n layers(ROOT, null);\n for (const p of asset.parts) {\n if (!isPivot(p)) continue;\n const own = extra.get(`${p.name}|opaque`);\n const { surface: _drop, ...rest } = p;\n parts.push({ ...rest, mesh: own ? merge(own) : null });\n layers(p.name, p.name);\n }\n return { ...asset, parts };\n}\n",
10
- "// The package version written into every GLB (`asset.generator`, XMP CreatorTool). Kept as a\n// constant because the library may not import package.json (rootDir is src); version.test.ts\n// fails the gate when the two disagree, and `bun run release` stamps both.\n\nexport const VERSION = '0.1.0';\nexport const GENERATOR = `@developerz.ai/ts23d ${VERSION}`;\n",
11
- "// Provenance inside the file: `asset.generator` with the version, `asset.copyright`, and an XMP\n// packet (KHR_xmp_json_ld, Ratified) with title, description, creators, rights, licence and the\n// recipe's sources — what Sketchfab, Blender and asset stores read. No dates: bytes stay\n// deterministic.\n\nimport type { Json } from './bin-writer.ts';\nimport { GENERATOR } from './version.ts';\n\nexport interface GlbMeta {\n /** Default: the asset name. */\n readonly title?: string;\n readonly description?: string;\n readonly creators?: readonly string[];\n /** Goes to `asset.copyright` and `dc:rights`, e.g. \"© 2026 Jane Doe\". */\n readonly copyright?: string;\n /** SPDX id or licence URL → `xmpRights:UsageTerms`, e.g. \"CC-BY-4.0\". */\n readonly license?: string;\n /** Where the numbers came from (the recipe's `sources`) → `dc:relation`. */\n readonly sources?: readonly string[];\n}\n\nconst XMP = 'KHR_xmp_json_ld';\nconst alt = (value: string): Json => ({\n '@type': 'rdf:Alt',\n 'rdf:_1': { '@language': 'x-default', '@value': value },\n});\n\n/** `asset` block, plus root `extensions` and the extension name when an XMP packet is written. */\nexport function metadata(\n name: string,\n meta: GlbMeta | undefined,\n): { asset: Json; extensions?: Json; used: string[] } {\n const asset: Json = {\n version: '2.0',\n generator: GENERATOR,\n ...(meta?.copyright ? { copyright: meta.copyright } : {}),\n };\n if (!meta) return { asset, used: [] };\n const packet: Json = {\n '@context': {\n dc: 'http://purl.org/dc/elements/1.1/',\n rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',\n xmp: 'http://ns.adobe.com/xap/1.0/',\n xmpRights: 'http://ns.adobe.com/xap/1.0/rights/',\n },\n 'dc:title': alt(meta.title ?? name),\n ...(meta.description ? { 'dc:description': alt(meta.description) } : {}),\n ...(meta.creators?.length ? { 'dc:creator': { '@list': [...meta.creators] } } : {}),\n ...(meta.copyright ? { 'dc:rights': alt(meta.copyright) } : {}),\n ...(meta.license ? { 'xmpRights:UsageTerms': alt(meta.license) } : {}),\n ...(meta.sources?.length ? { 'dc:relation': { '@set': [...meta.sources] } } : {}),\n 'xmp:CreatorTool': GENERATOR,\n };\n return {\n asset: { ...asset, extensions: { [XMP]: { packet: 0 } } },\n extensions: { [XMP]: { packets: [packet] } },\n used: [XMP],\n };\n}\n",
12
- "// Bakes a part's Motion into one glTF sampler + channel of the looping `run` clip.\n// Seamless by construction: every motion is rounded to a WHOLE number of cycles over the clip,\n// so the last key equals the first (a 0.8 rps wheel over 4 s = 3 turns, not 3.2 — no jump at\n// the loop point). Spins get ≥ 12 keys per turn so LINEAR quaternion interpolation never takes\n// the short way round. Time arrays are shared between channels of equal key count.\n\nimport type { Motion } from '../core/index.ts';\nimport { quatFromAxisAngle } from '../core/index.ts';\nimport type { BinWriter, Json } from './bin-writer.ts';\n\nexport const LOOP_SECONDS = 4;\n\n/** Whole cycles of `rate` (Hz or rev/s) over the clip, at least one. */\nexport const cyclesOf = (rate: number): number =>\n Math.max(1, Math.round(Math.abs(rate) * LOOP_SECONDS)) * Math.sign(rate || 1);\n\nconst timeAccessors = new WeakMap<BinWriter, Map<number, number>>();\nfunction times(bin: BinWriter, keys: number): { input: number; t: Float32Array } {\n const t = new Float32Array(keys + 1).map((_, i) => (i / keys) * LOOP_SECONDS);\n const byBin = timeAccessors.get(bin) ?? new Map<number, number>();\n timeAccessors.set(bin, byBin);\n let input = byBin.get(keys);\n if (input === undefined) {\n input = bin.accessor(t, 'SCALAR', undefined, true);\n byBin.set(keys, input);\n }\n return { input, t };\n}\n\nexport function motionChannel(\n bin: BinWriter,\n motion: Motion,\n node: number,\n rest: readonly number[],\n): { sampler: Json; channel: Json } {\n const rate = motion.kind === 'spin' ? motion.rps : motion.hz;\n const cycles = cyclesOf(rate);\n const keys = Math.max(24, Math.abs(cycles) * (motion.kind === 'spin' ? 12 : 16));\n const { input, t } = times(bin, keys);\n const phase = (time: number): number => (time / LOOP_SECONDS) * cycles * Math.PI * 2;\n // Two-sided: −1..1 around rest. One-way: 0..1, starting and ending at rest (seamless loop).\n const wave = (time: number): number =>\n motion.kind !== 'spin' && motion.oneWay\n ? (1 - Math.cos(phase(time))) / 2\n : Math.sin(phase(time));\n if (motion.kind === 'slide') {\n const values = new Float32Array((keys + 1) * 3);\n t.forEach((time, i) => {\n const s = wave(time);\n values.set(\n [0, 1, 2].map((k) => (rest[k] ?? 0) + (motion.offset[k] ?? 0) * s),\n i * 3,\n );\n });\n return {\n sampler: { input, output: bin.accessor(values, 'VEC3'), interpolation: 'LINEAR' },\n channel: { target: { node, path: 'translation' } },\n };\n }\n const values = new Float32Array((keys + 1) * 4);\n const peak = motion.kind === 'sway' ? (motion.degrees * Math.PI) / 180 : 0;\n t.forEach((time, i) => {\n const angle = motion.kind === 'spin' ? phase(time) : peak * wave(time);\n values.set(quatFromAxisAngle(motion.axis, angle), i * 4);\n });\n return {\n sampler: { input, output: bin.accessor(values, 'VEC4'), interpolation: 'LINEAR' },\n channel: { target: { node, path: 'rotation' } },\n };\n}\n",
13
- "// Runs the mesh optimiser (passes/optimize: weld → vertex cache → vertex fetch) over every part\n// headed for the GLB, and sums what it did into one report the CLI and manifest can print.\n\nimport type { CompiledAsset } from '../core/index.ts';\nimport { type OptimizeOptions, type OptimizeReport, optimize } from '../passes/index.ts';\n\nexport interface PartOptimizeReport extends OptimizeReport {\n readonly part: string;\n}\n\n/** Totals over all parts; ACMR/ATVR are triangle-weighted means. */\nexport interface ExportReport {\n readonly optimized: boolean;\n readonly verticesBefore: number;\n readonly verticesAfter: number;\n readonly trianglesBefore: number;\n readonly trianglesAfter: number;\n readonly degenerate: number;\n readonly duplicate: number;\n readonly acmrBefore: number;\n readonly acmr: number;\n readonly atvrBefore: number;\n readonly atvr: number;\n readonly parts: readonly PartOptimizeReport[];\n}\n\nexport function summarize(parts: readonly PartOptimizeReport[], optimized: boolean): ExportReport {\n const sum = (f: (r: PartOptimizeReport) => number): number => parts.reduce((s, r) => s + f(r), 0);\n const tb = sum((r) => r.trianglesBefore);\n const ta = sum((r) => r.trianglesAfter);\n const mean = (f: (r: PartOptimizeReport) => number, by: number, w: 'b' | 'a'): number =>\n by ? sum((r) => f(r) * (w === 'b' ? r.trianglesBefore : r.trianglesAfter)) / by : 0;\n return {\n optimized,\n verticesBefore: sum((r) => r.verticesBefore),\n verticesAfter: sum((r) => r.verticesAfter),\n trianglesBefore: tb,\n trianglesAfter: ta,\n degenerate: sum((r) => r.degenerate),\n duplicate: sum((r) => r.duplicate),\n acmrBefore: mean((r) => r.acmrBefore, tb, 'b'),\n acmr: mean((r) => r.acmr, ta, 'a'),\n atvrBefore: mean((r) => r.atvrBefore, tb, 'b'),\n atvr: mean((r) => r.atvr, ta, 'a'),\n parts,\n };\n}\n\n/** Optimise every part mesh. `false` passes meshes through and reports them as-is. */\nexport function optimizeParts(\n asset: CompiledAsset,\n o: OptimizeOptions | false,\n): { asset: CompiledAsset; report: ExportReport } {\n const reports: PartOptimizeReport[] = [];\n const parts = asset.parts.map((p) => {\n if (!p.mesh || p.mesh.indices.length === 0) return p;\n if (o === false) {\n const v = p.mesh.positions.length / 3;\n const t = p.mesh.indices.length / 3;\n reports.push({\n part: p.name,\n verticesBefore: v,\n verticesAfter: v,\n trianglesBefore: t,\n trianglesAfter: t,\n degenerate: 0,\n duplicate: 0,\n acmrBefore: 0,\n acmr: 0,\n atvrBefore: 0,\n atvr: 0,\n });\n return p;\n }\n const { mesh, report } = optimize(p.mesh, o);\n reports.push({ part: p.name, ...report });\n return { ...p, mesh };\n });\n return { asset: { ...asset, parts }, report: summarize(reports, o !== false) };\n}\n",
14
- "// Per-vertex tangents (glTF TANGENT, VEC4) for normal-mapped meshes: Lengyel's UV-derivative\n// method, Gram-Schmidt against the vertex normal, w = handedness. The bitangent cross(N, T) · w\n// points toward DECREASING glTF v (the \"green up\" convention the painter writes). Identical to\n// MikkTSpace on flat-shaded quads; close, not bit-equal, on smooth curved surfaces.\n\nimport type { Mesh } from '../core/index.ts';\n\nexport function tangentsOf(m: Mesh): Float32Array {\n const n = m.positions.length / 3;\n const tan = new Float32Array(n * 3);\n const bit = new Float32Array(n * 3);\n const P = m.positions;\n const U = m.uvs;\n for (let t = 0; t < m.indices.length; t += 3) {\n const a = m.indices[t] ?? 0;\n const b = m.indices[t + 1] ?? 0;\n const c = m.indices[t + 2] ?? 0;\n const e1x = (P[b * 3] ?? 0) - (P[a * 3] ?? 0);\n const e1y = (P[b * 3 + 1] ?? 0) - (P[a * 3 + 1] ?? 0);\n const e1z = (P[b * 3 + 2] ?? 0) - (P[a * 3 + 2] ?? 0);\n const e2x = (P[c * 3] ?? 0) - (P[a * 3] ?? 0);\n const e2y = (P[c * 3 + 1] ?? 0) - (P[a * 3 + 1] ?? 0);\n const e2z = (P[c * 3 + 2] ?? 0) - (P[a * 3 + 2] ?? 0);\n const du1 = (U[b * 2] ?? 0) - (U[a * 2] ?? 0);\n const dv1 = -((U[b * 2 + 1] ?? 0) - (U[a * 2 + 1] ?? 0));\n const du2 = (U[c * 2] ?? 0) - (U[a * 2] ?? 0);\n const dv2 = -((U[c * 2 + 1] ?? 0) - (U[a * 2 + 1] ?? 0));\n const det = du1 * dv2 - du2 * dv1;\n if (Math.abs(det) < 1e-12) continue;\n const r = 1 / det;\n const tx = (e1x * dv2 - e2x * dv1) * r;\n const ty = (e1y * dv2 - e2y * dv1) * r;\n const tz = (e1z * dv2 - e2z * dv1) * r;\n const bx = (e2x * du1 - e1x * du2) * r;\n const by = (e2y * du1 - e1y * du2) * r;\n const bz = (e2z * du1 - e1z * du2) * r;\n for (const v of [a, b, c]) {\n tan[v * 3] = (tan[v * 3] ?? 0) + tx;\n tan[v * 3 + 1] = (tan[v * 3 + 1] ?? 0) + ty;\n tan[v * 3 + 2] = (tan[v * 3 + 2] ?? 0) + tz;\n bit[v * 3] = (bit[v * 3] ?? 0) + bx;\n bit[v * 3 + 1] = (bit[v * 3 + 1] ?? 0) + by;\n bit[v * 3 + 2] = (bit[v * 3 + 2] ?? 0) + bz;\n }\n }\n const out = new Float32Array(n * 4);\n for (let v = 0; v < n; v++) {\n const nx = m.normals[v * 3] ?? 0;\n const ny = m.normals[v * 3 + 1] ?? 0;\n const nz = m.normals[v * 3 + 2] ?? 1;\n let tx = tan[v * 3] ?? 0;\n let ty = tan[v * 3 + 1] ?? 0;\n let tz = tan[v * 3 + 2] ?? 0;\n const d = nx * tx + ny * ty + nz * tz;\n tx -= nx * d;\n ty -= ny * d;\n tz -= nz * d;\n let len = Math.hypot(tx, ty, tz);\n if (len < 1e-8) {\n // No usable UV gradient: any unit vector perpendicular to the normal.\n [tx, ty, tz] = Math.abs(nx) < 0.9 ? [0, -nz, ny] : [nz, 0, -nx];\n len = Math.hypot(tx, ty, tz) || 1;\n }\n tx /= len;\n ty /= len;\n tz /= len;\n // Handedness: does cross(N, T) agree with the accumulated bitangent?\n const cx = ny * tz - nz * ty;\n const cy = nz * tx - nx * tz;\n const cz = nx * ty - ny * tx;\n const w = cx * (bit[v * 3] ?? 0) + cy * (bit[v * 3 + 1] ?? 0) + cz * (bit[v * 3 + 2] ?? 0);\n out.set([tx, ty, tz, w < 0 ? -1 : 1], v * 4);\n }\n return out;\n}\n",
15
- "// One mesh → one glTF primitive: POSITION (with bounds), NORMAL, TEXCOORD_0, COLOR_0 as unorm16\n// RGBA, TANGENT only when a normal map is bound, and the smallest index type that fits.\n\nimport type { Mesh } from '../core/index.ts';\nimport { ARRAY_BUFFER, type BinWriter, ELEMENT_ARRAY_BUFFER, type Json } from './bin-writer.ts';\nimport { tangentsOf } from './tangents.ts';\n\nexport function writePrimitive(bin: BinWriter, m: Mesh, material: number, tangents: boolean): Json {\n // COLOR_0 as normalised unsigned short RGBA: 8 bytes/vertex instead of 16, no banding in\n // darks (8-bit would). VEC4 because vertex attributes must be 4-byte aligned.\n const colors = new Uint16Array((m.colors.length / 3) * 4);\n const q = (v: number): number => Math.round(Math.min(1, Math.max(0, v)) * 65535);\n for (let i = 0; i < m.colors.length / 3; i++)\n colors.set(\n [q(m.colors[i * 3] ?? 1), q(m.colors[i * 3 + 1] ?? 1), q(m.colors[i * 3 + 2] ?? 1), 65535],\n i * 4,\n );\n return {\n attributes: {\n POSITION: bin.accessor(m.positions, 'VEC3', ARRAY_BUFFER, true),\n NORMAL: bin.accessor(m.normals, 'VEC3', ARRAY_BUFFER),\n TEXCOORD_0: bin.accessor(m.uvs, 'VEC2', ARRAY_BUFFER),\n COLOR_0: bin.accessor(colors, 'VEC4', ARRAY_BUFFER, false, true),\n // A bound normal map needs a tangent space (validator S10 / G15).\n ...(tangents ? { TANGENT: bin.accessor(tangentsOf(m), 'VEC4', ARRAY_BUFFER) } : {}),\n },\n // 16-bit indices whenever the primitive allows: half the bytes, every engine reads them.\n indices: bin.accessor(\n m.positions.length / 3 <= 65535 ? Uint16Array.from(m.indices) : m.indices,\n 'SCALAR',\n ELEMENT_ARRAY_BUFFER,\n ),\n material,\n };\n}\n",
16
- "// The trim sheet in glTF: three images (albedo sRGB, normal + ORM linear), three textures and one\n// sampler (REPEAT along U so strips tile, CLAMP along V so the atlas never wraps rows, trilinear\n// mips). Embedded: PNGs ride in the BIN chunk after the geometry (self-contained single files).\n// External: images reference `<prefix>_{albedo,normal,orm}.png` by URI, so fifty assets share one\n// texture set on disk and in GPU memory — the point of the trim sheet. Write the PNGs once with\n// `sheetPngs`. Texture indices are fixed: 0 albedo, 1 normal, 2 ORM (materials.ts binds them).\n\nimport { encodePng } from '../core/index.ts';\nimport type { PaintedSheet } from '../material/index.ts';\nimport type { Json } from './bin-writer.ts';\n\nexport type SheetMap = 'albedo' | 'normal' | 'orm';\nexport const SHEET_MAPS: readonly SheetMap[] = ['albedo', 'normal', 'orm'];\n\n/** Reference a shared sheet by URI instead of embedding it. */\nexport interface ExternalSheet {\n readonly external: true;\n /** URI prefix relative to the .glb, e.g. `../textures/trim_sheet`. Default `trim_sheet`. */\n readonly prefix?: string;\n}\n\nexport type SheetBinding = PaintedSheet | ExternalSheet;\n\nexport const sheetFileName = (map: SheetMap, prefix = 'trim_sheet'): string =>\n `${prefix}_${map}.png`;\n\nconst LINEAR = 9729;\nconst LINEAR_MIPMAP_LINEAR = 9987;\nconst REPEAT = 10497;\nconst CLAMP_TO_EDGE = 33071;\n\nconst pngCache = new WeakMap<PaintedSheet, Readonly<Record<SheetMap, Uint8Array>>>();\n\n/** PNG bytes of each map, encoded once per sheet (every LOD's GLB reuses them). */\nexport function sheetPngs(sheet: PaintedSheet): Readonly<Record<SheetMap, Uint8Array>> {\n const hit = pngCache.get(sheet);\n if (hit) return hit;\n const pngs = {\n albedo: encodePng(sheet.size, sheet.size, sheet.albedo),\n normal: encodePng(sheet.size, sheet.size, sheet.normal),\n orm: encodePng(sheet.size, sheet.size, sheet.orm),\n };\n pngCache.set(sheet, pngs);\n return pngs;\n}\n\nconst isExternal = (s: SheetBinding): s is ExternalSheet => 'external' in s;\n\n/**\n * glTF `images` / `textures` / `samplers` for the sheet. Embedded image bytes are returned as\n * `tail`, to append to the BIN chunk at `offset` (4-aligned); their bufferViews go into `views`.\n */\nexport function sheetGltf(\n sheet: SheetBinding,\n views: Json[],\n offset: number,\n): { json: Json; tail: Uint8Array } {\n const textures = SHEET_MAPS.map((_, i) => ({ sampler: 0, source: i }));\n const samplers = [\n { magFilter: LINEAR, minFilter: LINEAR_MIPMAP_LINEAR, wrapS: REPEAT, wrapT: CLAMP_TO_EDGE },\n ];\n if (isExternal(sheet)) {\n const images = SHEET_MAPS.map((m) => ({\n name: `trim_sheet_${m}`,\n uri: sheetFileName(m, sheet.prefix),\n }));\n return { json: { images, textures, samplers }, tail: new Uint8Array() };\n }\n const pngs = sheetPngs(sheet);\n const parts: Uint8Array[] = [];\n const images: Json[] = [];\n let at = offset;\n for (const m of SHEET_MAPS) {\n const png = pngs[m];\n views.push({ buffer: 0, byteOffset: at, byteLength: png.byteLength });\n images.push({ name: `trim_sheet_${m}`, bufferView: views.length - 1, mimeType: 'image/png' });\n const pad = (4 - (png.byteLength % 4)) % 4;\n parts.push(png, new Uint8Array(pad));\n at += png.byteLength + pad;\n }\n const tail = new Uint8Array(at - offset);\n let o = 0;\n for (const p of parts) {\n tail.set(p, o);\n o += p.byteLength;\n }\n return { json: { images, textures, samplers }, tail };\n}\n",
17
- "// glTF 2.0 binary writer. One material (the trim sheet) for the whole asset, one node per part\n// with its pivot as translation, and each part's motion baked as a looping animation clip.\n// Extras a stock viewer understands: light sockets → KHR_lights_punctual, glowing parts →\n// emissive (+ KHR_materials_emissive_strength), provenance → asset.copyright + KHR_xmp_json_ld.\n// Zero dependencies and byte-deterministic: same CompiledAsset in, same bytes out.\n\nimport type { CompiledAsset, Part } from '../core/index.ts';\nimport { quatFromAxisAngle, Ts23dError } from '../core/index.ts';\nimport type { OptimizeOptions } from '../passes/index.ts';\nimport { BinWriter, type Json } from './bin-writer.ts';\nimport { concat, packGlb } from './container.ts';\nimport { LIGHTS, lightOf } from './lights.ts';\nimport { EMISSIVE_STRENGTH, type GlowRule, glowMaterial, materialsFor } from './materials.ts';\nimport { globRe, glowLayer, mergeToPivots } from './merge-pivots.ts';\nimport { type GlbMeta, metadata } from './metadata.ts';\nimport { motionChannel } from './motion.ts';\nimport { type ExportReport, optimizeParts } from './optimize-parts.ts';\nimport { writePrimitive } from './primitive.ts';\nimport { type SheetBinding, sheetGltf } from './textures.ts';\n\n// Viewers auto-play the FIRST clip and glTF has no \"paused\" flag, so the first clip is `rest`: two\n// keys holding the root's rest rotation. The file opens still; pick `run` to play it.\n// Authoring frame: Z up, +X front. glTF: Y up, +Z front, +X = the asset's left. This root\n// rotation maps +X→+Z, +Z→+Y, +Y→+X (verified numerically), so assets face forward in engines.\nconst Z_UP_TO_Y_UP = [-0.5, -0.5, -0.5, 0.5];\nfunction restClip(bin: BinWriter): Json {\n const input = bin.accessor(new Float32Array([0, 1]), 'SCALAR', undefined, true);\n const output = bin.accessor(new Float32Array([...Z_UP_TO_Y_UP, ...Z_UP_TO_Y_UP]), 'VEC4');\n return {\n name: 'rest',\n samplers: [{ input, output, interpolation: 'STEP' }],\n channels: [{ sampler: 0, target: { node: 0, path: 'rotation' } }],\n };\n}\n\nexport interface GlbOptions {\n /** Keep every part as its own node (debugging, per-part picking). Default merges to pivots. */\n readonly keepParts?: boolean;\n /**\n * Bake each part's `motion` into a looping `run` clip. Off by default: glTF has no autoplay\n * flag and most viewers play the first clip, while engines usually drive the named pivots\n * from game code. Turn it on for previews, cutscenes and ambient props.\n */\n readonly animations?: boolean;\n /**\n * Bind the painted trim sheet to every material: a `PaintedSheet` embeds the three PNGs (one\n * self-contained file); `{ external: true, prefix? }` references shared `trim_sheet_*.png` by\n * URI. Omitted: no textures, byte-identical to the untextured output.\n */\n readonly sheet?: SheetBinding;\n /**\n * Weld + vertex-cache + vertex-fetch optimisation per primitive (passes/optimize). On by\n * default; `false` writes the meshes exactly as compiled (debugging the IR).\n */\n readonly optimize?: boolean | OptimizeOptions;\n /** Parts that emit light (lamp lenses, lit windows): one emissive material per rule. */\n readonly glow?: readonly GlowRule[];\n /** Provenance: asset.copyright + an XMP packet (title, creators, licence, sources). */\n readonly meta?: GlbMeta;\n}\n\n/** The GLB bytes plus what the optimiser did (vertex counts, ACMR before/after, per part). */\nexport interface GlbResult {\n readonly glb: Uint8Array;\n readonly report: ExportReport;\n}\n\nexport function toGlb(input: CompiledAsset, o: GlbOptions = {}): Uint8Array {\n return exportGlb(input, o).glb;\n}\n\nfunction checkGlow(rules: readonly GlowRule[]): void {\n for (const r of rules)\n if ((r.strength ?? 4) < 0 || (r.color ?? [0, 0, 0]).some((c) => c < 0 || c > 1))\n throw new Ts23dError('T3D_RECIPE_INVALID', {\n cause: `glow rule for ${JSON.stringify(r.parts)} has a colour outside 0..1 or a negative strength`,\n fix: 'colour is linear 0..1 (hex() converts sRGB); brightness goes in `strength`',\n });\n}\n\nexport function exportGlb(input: CompiledAsset, o: GlbOptions = {}): GlbResult {\n const glow = o.glow ?? input.glow ?? [];\n checkGlow(glow);\n const opt = o.optimize === false ? false : o.optimize === true ? {} : (o.optimize ?? {});\n const merged = o.keepParts\n ? input\n : mergeToPivots(\n input,\n glow.map((g) => g.parts),\n );\n const { asset, report } = optimizeParts(merged, opt);\n // optimizeParts copies parts: carry the glow tag across by position.\n const glowRes = glow.map((g) => g.parts.map(globRe));\n const glowOf = (p: Part, i: number): number =>\n glowLayer.get(merged.parts[i] ?? p) ??\n (o.keepParts ? glowRes.findIndex((rs) => rs.some((r) => r.test(p.name))) : -1);\n const mats = materialsFor(\n new Set(asset.parts.flatMap((p) => (p.surface ? [p.surface] : []))),\n o.sheet !== undefined,\n );\n const glowAt = mats.materials.length;\n const materials = [\n ...mats.materials,\n ...glow.map((g, i) => glowMaterial(g, i, o.sheet !== undefined)),\n ];\n const bin = new BinWriter();\n const meshes: Json[] = [];\n const nodes: Json[] = [{ name: asset.name, children: [] as number[] }];\n const index = new Map<string, number>();\n const samplers: Json[] = [];\n const channels: Json[] = [];\n const lights: Json[] = [];\n const attach = (parentId: number, id: number): void => {\n const parent = nodes[parentId];\n if (!parent) return;\n parent['children'] = [...((parent['children'] as number[] | undefined) ?? []), id];\n };\n\n asset.parts.forEach((part: Part, i) => {\n const node: Json = { name: part.name, translation: [...part.at] };\n if (part.yaw) node['rotation'] = [...quatFromAxisAngle([0, 0, 1], part.yaw)];\n if (part.emitter || part.socket) {\n node['extras'] = {\n ts23d: {\n ...(part.emitter ? { emitter: part.emitter } : {}),\n ...(part.socket ? { socket: part.socket } : {}),\n },\n };\n }\n if (part.mesh && part.mesh.indices.length > 0) {\n const g = glowOf(part, i);\n const material = g >= 0 ? glowAt + g : (mats.index.get(part.surface ?? 'opaque') ?? 0);\n meshes.push({\n name: part.name,\n primitives: [writePrimitive(bin, part.mesh, material, o.sheet !== undefined)],\n });\n node['mesh'] = meshes.length - 1;\n }\n nodes.push(node);\n const id = nodes.length - 1;\n index.set(part.name, id);\n attach(part.parent === null ? 0 : (index.get(part.parent) ?? 0), id);\n const lit = lightOf(part);\n if (lit) {\n lights.push(lit.light);\n nodes.push({\n name: `${part.name}_light`,\n rotation: [...lit.rotation],\n extensions: { [LIGHTS]: { light: lights.length - 1 } },\n });\n attach(id, nodes.length - 1);\n }\n if (part.motion && o.animations) {\n const { sampler, channel } = motionChannel(bin, part.motion, id, part.at);\n samplers.push(sampler);\n channels.push({ ...channel, sampler: samplers.length - 1 });\n }\n });\n\n // Every accessor — the rest clip's included — must be written BEFORE the buffer is sealed.\n const animations = channels.length ? [restClip(bin), { name: 'run', samplers, channels }] : [];\n const geometry = bin.bytes();\n const tex = o.sheet ? sheetGltf(o.sheet, bin.views, geometry.byteLength) : null;\n const body = tex?.tail.byteLength ? concat(geometry, tex.tail) : geometry;\n const meta = metadata(asset.name, o.meta ?? input.meta);\n const used = [\n ...mats.extensionsUsed,\n ...(glow.some((g) => (g.strength ?? 4) !== 1) ? [EMISSIVE_STRENGTH] : []),\n ...(lights.length ? [LIGHTS] : []),\n ...meta.used,\n ].sort();\n const extensions: Json = {\n ...(lights.length ? { [LIGHTS]: { lights } } : {}),\n ...(meta.extensions ?? {}),\n };\n const root = nodes[0];\n if (root) root['rotation'] = Z_UP_TO_Y_UP;\n const gltf: Json = {\n asset: meta.asset,\n extras: {\n kind: asset.kind,\n lod: asset.lod,\n units: 'metres',\n up: 'Z (rotated to glTF Y-up at the root)',\n },\n ...(used.length ? { extensionsUsed: used } : {}),\n ...(Object.keys(extensions).length ? { extensions } : {}),\n scene: 0,\n scenes: [{ name: asset.name, nodes: [0] }],\n nodes,\n meshes,\n materials,\n ...(tex ? tex.json : {}),\n buffers: [{ byteLength: body.byteLength }],\n bufferViews: bin.views,\n accessors: bin.accessors,\n ...(animations.length ? { animations } : {}),\n };\n return { glb: packGlb(gltf, body), report };\n}\n"
18
- ],
19
- "mappings": "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",
20
- "debugId": "635FF0E967FF13E664756E2164756E21",
21
- "names": []
22
- }
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/cli/manifest.ts"],
4
- "sourcesContent": [
5
- "// manifest.json per asset: what an engine pipeline or an agent needs without opening a GLB —\n// files, triangles per LOD, pivots (the names game code binds to), emitters, surfaces, QA,\n// measures with their measured values, sources.\n\nimport type { Asset, CompiledAsset } from '../core/index.ts';\nimport { mergeToPivots } from '../export/index.ts';\nimport { type Finding, measure } from '../qa/index.ts';\n\nexport interface AssetManifest {\n readonly name: string;\n readonly kind: string;\n readonly description?: string;\n readonly tags: readonly string[];\n readonly files: {\n readonly lods: readonly string[];\n readonly hero?: string;\n readonly sheet?: string;\n readonly thumb?: string;\n };\n readonly triangles: readonly number[];\n readonly drawCalls: readonly number[];\n readonly pivots: readonly { name: string; parent: string | null; motion?: string }[];\n readonly emitters: readonly { name: string; kind: string; when: string }[];\n readonly sockets: readonly { name: string; kind: string; parent: string | null }[];\n readonly surfaces: readonly string[];\n readonly real?: { length: number; width: number; height: number };\n readonly measures: readonly {\n label: string;\n spec: number;\n measured: number | null;\n source?: string;\n }[];\n readonly sources: readonly string[];\n readonly qa: { readonly pass: boolean; readonly findings: readonly Finding[] };\n}\n\nconst tris = (a: CompiledAsset): number =>\n a.parts.reduce((s, p) => s + (p.mesh ? p.mesh.indices.length / 3 : 0), 0);\n\nexport function manifestOf(\n asset: Asset,\n lods: readonly CompiledAsset[],\n files: AssetManifest['files'],\n findings: readonly Finding[],\n): AssetManifest {\n const top = lods[0];\n const merged = top ? mergeToPivots(top) : null;\n return {\n name: asset.name,\n kind: asset.kind,\n ...(asset.description ? { description: asset.description } : {}),\n tags: asset.tags ?? [],\n files,\n triangles: lods.map(tris),\n // One draw per merged mesh, glowing parts in their own emissive layer (as the GLB writes them).\n drawCalls: lods.map(\n (l) =>\n mergeToPivots(\n l,\n (l.glow ?? []).map((g) => g.parts),\n ).parts.filter((p) => p.mesh).length,\n ),\n pivots: (merged?.parts ?? [])\n .filter((p) => !p.emitter && !p.socket)\n .map((p) => ({\n name: p.name,\n parent: p.parent,\n ...(p.motion ? { motion: p.motion.kind } : {}),\n })),\n emitters: (top?.parts ?? []).flatMap((p) =>\n p.emitter ? [{ name: p.name, kind: p.emitter.kind, when: p.emitter.when ?? 'always' }] : [],\n ),\n sockets: (top?.parts ?? []).flatMap((p) =>\n p.socket ? [{ name: p.name, kind: p.socket.kind, parent: p.parent }] : [],\n ),\n surfaces: [...new Set((top?.parts ?? []).map((p) => p.surface ?? 'opaque'))].sort(),\n ...(asset.real\n ? { real: { length: asset.real.length, width: asset.real.width, height: asset.real.height } }\n : {}),\n measures: (asset.real?.measures ?? []).map((m) => ({\n label: m.label,\n spec: m.value,\n measured: top ? measure(top, m) : null,\n ...(m.source ? { source: m.source } : {}),\n })),\n sources: asset.sources ?? [],\n qa: { pass: findings.length === 0, findings },\n };\n}\n"
6
- ],
7
- "mappings": ";;;;;;;;AAoCA,IAAM,OAAO,CAAC,MACZ,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,KAAK,EAAE,OAAO,EAAE,KAAK,QAAQ,SAAS,IAAI,IAAI,CAAC;AAEnE,SAAS,WAAU,CACxB,OACA,MACA,OACA,UACe;AAAA,EACf,MAAM,MAAM,KAAK;AAAA,EACjB,MAAM,SAAS,MAAM,eAAc,GAAG,IAAI;AAAA,EAC1C,OAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,MAAM,MAAM;AAAA,OACR,MAAM,cAAc,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;AAAA,IAC9D,MAAM,MAAM,QAAQ,CAAC;AAAA,IACrB;AAAA,IACA,WAAW,KAAK,IAAI,IAAI;AAAA,IAExB,WAAW,KAAK,IACd,CAAC,MACC,eACE,IACC,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,CACnC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,MAClC;AAAA,IACA,SAAS,QAAQ,SAAS,CAAC,GACxB,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,EACrC,IAAI,CAAC,OAAO;AAAA,MACX,MAAM,EAAE;AAAA,MACR,QAAQ,EAAE;AAAA,SACN,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;AAAA,IAC9C,EAAE;AAAA,IACJ,WAAW,KAAK,SAAS,CAAC,GAAG,QAAQ,CAAC,MACpC,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,QAAQ,SAAS,CAAC,IAAI,CAAC,CAC5F;AAAA,IACA,UAAU,KAAK,SAAS,CAAC,GAAG,QAAQ,CAAC,MACnC,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,OAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAC1E;AAAA,IACA,UAAU,CAAC,GAAG,IAAI,KAAK,KAAK,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,QAAQ,CAAC,CAAC,EAAE,KAAK;AAAA,OAC9E,MAAM,OACN,EAAE,MAAM,EAAE,QAAQ,MAAM,KAAK,QAAQ,OAAO,MAAM,KAAK,OAAO,QAAQ,MAAM,KAAK,OAAO,EAAE,IAC1F,CAAC;AAAA,IACL,WAAW,MAAM,MAAM,YAAY,CAAC,GAAG,IAAI,CAAC,OAAO;AAAA,MACjD,OAAO,EAAE;AAAA,MACT,MAAM,EAAE;AAAA,MACR,UAAU,MAAM,SAAQ,KAAK,CAAC,IAAI;AAAA,SAC9B,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,IAAI,CAAC;AAAA,IACzC,EAAE;AAAA,IACF,SAAS,MAAM,WAAW,CAAC;AAAA,IAC3B,IAAI,EAAE,MAAM,SAAS,WAAW,GAAG,SAAS;AAAA,EAC9C;AAAA;",
8
- "debugId": "E9A05EE7585826EF64756E2164756E21",
9
- "names": []
10
- }