@daidr/minecraft-skin-renderer 0.1.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 (150) hide show
  1. package/README.md +247 -0
  2. package/dist/animation/AnimationController.d.mts +15 -0
  3. package/dist/animation/AnimationController.d.mts.map +1 -0
  4. package/dist/animation/AnimationController.mjs +146 -0
  5. package/dist/animation/AnimationController.mjs.map +1 -0
  6. package/dist/animation/easing.mjs +9 -0
  7. package/dist/animation/easing.mjs.map +1 -0
  8. package/dist/animation/presets/fly.mjs +176 -0
  9. package/dist/animation/presets/fly.mjs.map +1 -0
  10. package/dist/animation/presets/idle.mjs +114 -0
  11. package/dist/animation/presets/idle.mjs.map +1 -0
  12. package/dist/animation/presets/index.mjs +7 -0
  13. package/dist/animation/presets/run.mjs +126 -0
  14. package/dist/animation/presets/run.mjs.map +1 -0
  15. package/dist/animation/presets/utils.mjs +166 -0
  16. package/dist/animation/presets/utils.mjs.map +1 -0
  17. package/dist/animation/presets/walk.mjs +76 -0
  18. package/dist/animation/presets/walk.mjs.map +1 -0
  19. package/dist/animation/types.d.mts +50 -0
  20. package/dist/animation/types.d.mts.map +1 -0
  21. package/dist/animation/types.mjs +22 -0
  22. package/dist/animation/types.mjs.map +1 -0
  23. package/dist/core/camera/Camera.d.mts +33 -0
  24. package/dist/core/camera/Camera.d.mts.map +1 -0
  25. package/dist/core/camera/Camera.mjs +77 -0
  26. package/dist/core/camera/Camera.mjs.map +1 -0
  27. package/dist/core/camera/OrbitControls.d.mts +50 -0
  28. package/dist/core/camera/OrbitControls.d.mts.map +1 -0
  29. package/dist/core/camera/OrbitControls.mjs +170 -0
  30. package/dist/core/camera/OrbitControls.mjs.map +1 -0
  31. package/dist/core/math/index.mjs +6 -0
  32. package/dist/core/math/mat4.d.mts +61 -0
  33. package/dist/core/math/mat4.d.mts.map +1 -0
  34. package/dist/core/math/mat4.mjs +513 -0
  35. package/dist/core/math/mat4.mjs.map +1 -0
  36. package/dist/core/math/quat.d.mts +61 -0
  37. package/dist/core/math/quat.d.mts.map +1 -0
  38. package/dist/core/math/quat.mjs +360 -0
  39. package/dist/core/math/quat.mjs.map +1 -0
  40. package/dist/core/math/utils.d.mts +43 -0
  41. package/dist/core/math/utils.d.mts.map +1 -0
  42. package/dist/core/math/utils.mjs +85 -0
  43. package/dist/core/math/utils.mjs.map +1 -0
  44. package/dist/core/math/vec3.d.mts +61 -0
  45. package/dist/core/math/vec3.d.mts.map +1 -0
  46. package/dist/core/math/vec3.mjs +198 -0
  47. package/dist/core/math/vec3.mjs.map +1 -0
  48. package/dist/core/plugins/registry.mjs +29 -0
  49. package/dist/core/plugins/registry.mjs.map +1 -0
  50. package/dist/core/plugins/types.d.mts +34 -0
  51. package/dist/core/plugins/types.d.mts.map +1 -0
  52. package/dist/core/renderer/registry.d.mts +46 -0
  53. package/dist/core/renderer/registry.d.mts.map +1 -0
  54. package/dist/core/renderer/registry.mjs +46 -0
  55. package/dist/core/renderer/registry.mjs.map +1 -0
  56. package/dist/core/renderer/shader-composer.mjs +30 -0
  57. package/dist/core/renderer/shader-composer.mjs.map +1 -0
  58. package/dist/core/renderer/types.d.mts +172 -0
  59. package/dist/core/renderer/types.d.mts.map +1 -0
  60. package/dist/core/renderer/types.mjs +90 -0
  61. package/dist/core/renderer/types.mjs.map +1 -0
  62. package/dist/core/renderer/utils.mjs +20 -0
  63. package/dist/core/renderer/utils.mjs.map +1 -0
  64. package/dist/core/renderer/webgl/WebGLBuffer.mjs +57 -0
  65. package/dist/core/renderer/webgl/WebGLBuffer.mjs.map +1 -0
  66. package/dist/core/renderer/webgl/WebGLPipeline.mjs +259 -0
  67. package/dist/core/renderer/webgl/WebGLPipeline.mjs.map +1 -0
  68. package/dist/core/renderer/webgl/WebGLRenderer.mjs +140 -0
  69. package/dist/core/renderer/webgl/WebGLRenderer.mjs.map +1 -0
  70. package/dist/core/renderer/webgl/WebGLTexture.mjs +87 -0
  71. package/dist/core/renderer/webgl/WebGLTexture.mjs.map +1 -0
  72. package/dist/core/renderer/webgl/plugin.d.mts +8 -0
  73. package/dist/core/renderer/webgl/plugin.d.mts.map +1 -0
  74. package/dist/core/renderer/webgl/plugin.mjs +24 -0
  75. package/dist/core/renderer/webgl/plugin.mjs.map +1 -0
  76. package/dist/core/renderer/webgl/shaders/index.mjs +81 -0
  77. package/dist/core/renderer/webgl/shaders/index.mjs.map +1 -0
  78. package/dist/core/renderer/webgpu/WebGPUBuffer.mjs +52 -0
  79. package/dist/core/renderer/webgpu/WebGPUBuffer.mjs.map +1 -0
  80. package/dist/core/renderer/webgpu/WebGPUPipeline.mjs +167 -0
  81. package/dist/core/renderer/webgpu/WebGPUPipeline.mjs.map +1 -0
  82. package/dist/core/renderer/webgpu/WebGPURenderer.mjs +299 -0
  83. package/dist/core/renderer/webgpu/WebGPURenderer.mjs.map +1 -0
  84. package/dist/core/renderer/webgpu/WebGPUTexture.mjs +126 -0
  85. package/dist/core/renderer/webgpu/WebGPUTexture.mjs.map +1 -0
  86. package/dist/core/renderer/webgpu/plugin.d.mts +8 -0
  87. package/dist/core/renderer/webgpu/plugin.d.mts.map +1 -0
  88. package/dist/core/renderer/webgpu/plugin.mjs +35 -0
  89. package/dist/core/renderer/webgpu/plugin.mjs.map +1 -0
  90. package/dist/core/renderer/webgpu/shaders/index.mjs +84 -0
  91. package/dist/core/renderer/webgpu/shaders/index.mjs.map +1 -0
  92. package/dist/index.d.mts +16 -0
  93. package/dist/index.mjs +19 -0
  94. package/dist/model/PlayerModel.d.mts +8 -0
  95. package/dist/model/PlayerModel.d.mts.map +1 -0
  96. package/dist/model/PlayerModel.mjs +253 -0
  97. package/dist/model/PlayerModel.mjs.map +1 -0
  98. package/dist/model/bone-utils.mjs +3 -0
  99. package/dist/model/constants.mjs +20 -0
  100. package/dist/model/constants.mjs.map +1 -0
  101. package/dist/model/geometry/BoxGeometry.mjs +316 -0
  102. package/dist/model/geometry/BoxGeometry.mjs.map +1 -0
  103. package/dist/model/geometry/index.mjs +3 -0
  104. package/dist/model/index.mjs +10 -0
  105. package/dist/model/types.d.mts +64 -0
  106. package/dist/model/types.d.mts.map +1 -0
  107. package/dist/model/types.mjs +67 -0
  108. package/dist/model/types.mjs.map +1 -0
  109. package/dist/model/uv/CapeUV.mjs +25 -0
  110. package/dist/model/uv/CapeUV.mjs.map +1 -0
  111. package/dist/model/uv/SkinUV.mjs +104 -0
  112. package/dist/model/uv/SkinUV.mjs.map +1 -0
  113. package/dist/model/uv/common.mjs +147 -0
  114. package/dist/model/uv/common.mjs.map +1 -0
  115. package/dist/panorama.d.mts +2 -0
  116. package/dist/panorama.mjs +3 -0
  117. package/dist/plugins/panorama/PanoramaRenderer.mjs +94 -0
  118. package/dist/plugins/panorama/PanoramaRenderer.mjs.map +1 -0
  119. package/dist/plugins/panorama/SkyboxGeometry.mjs +132 -0
  120. package/dist/plugins/panorama/SkyboxGeometry.mjs.map +1 -0
  121. package/dist/plugins/panorama/plugin.d.mts +8 -0
  122. package/dist/plugins/panorama/plugin.d.mts.map +1 -0
  123. package/dist/plugins/panorama/plugin.mjs +13 -0
  124. package/dist/plugins/panorama/plugin.mjs.map +1 -0
  125. package/dist/plugins/panorama/shaders/webgl.mjs +59 -0
  126. package/dist/plugins/panorama/shaders/webgl.mjs.map +1 -0
  127. package/dist/plugins/panorama/shaders/webgpu.mjs +70 -0
  128. package/dist/plugins/panorama/shaders/webgpu.mjs.map +1 -0
  129. package/dist/texture/TextureLoader.d.mts +22 -0
  130. package/dist/texture/TextureLoader.d.mts.map +1 -0
  131. package/dist/texture/TextureLoader.mjs +114 -0
  132. package/dist/texture/TextureLoader.mjs.map +1 -0
  133. package/dist/viewer/BoneMatrixComputer.mjs +82 -0
  134. package/dist/viewer/BoneMatrixComputer.mjs.map +1 -0
  135. package/dist/viewer/RenderLoop.mjs +45 -0
  136. package/dist/viewer/RenderLoop.mjs.map +1 -0
  137. package/dist/viewer/RenderState.mjs +44 -0
  138. package/dist/viewer/RenderState.mjs.map +1 -0
  139. package/dist/viewer/ResourceManager.mjs +278 -0
  140. package/dist/viewer/ResourceManager.mjs.map +1 -0
  141. package/dist/viewer/SkinViewer.d.mts +98 -0
  142. package/dist/viewer/SkinViewer.d.mts.map +1 -0
  143. package/dist/viewer/SkinViewer.mjs +379 -0
  144. package/dist/viewer/SkinViewer.mjs.map +1 -0
  145. package/dist/viewer/index.mjs +7 -0
  146. package/dist/webgl.d.mts +2 -0
  147. package/dist/webgl.mjs +3 -0
  148. package/dist/webgpu.d.mts +2 -0
  149. package/dist/webgpu.mjs +3 -0
  150. package/package.json +75 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoxGeometry.mjs","names":[],"sources":["../../../src/model/geometry/BoxGeometry.ts"],"sourcesContent":["/**\n * Box geometry generation for Minecraft model parts\n */\n\nimport type { Vec3 } from \"../../core/math\";\nimport { BoneIndex, VERTEX_STRIDE } from \"../types\";\nimport type { BoxGeometry, BoxUV } from \"../types\";\nimport {\n SKIN_TEXTURE_WIDTH,\n SKIN_TEXTURE_HEIGHT,\n CAPE_TEXTURE_WIDTH,\n CAPE_TEXTURE_HEIGHT,\n UV_EDGE_INSET,\n} from \"../constants\";\n\n/** Face indices for a cube */\nenum Face {\n Front = 0, // +Z\n Back = 1, // -Z\n Left = 2, // -X\n Right = 3, // +X\n Top = 4, // +Y\n Bottom = 5, // -Y\n}\n\n/** Normal vectors for each face */\nconst FACE_NORMALS: Vec3[] = [\n [0, 0, 1], // Front\n [0, 0, -1], // Back\n [-1, 0, 0], // Left\n [1, 0, 0], // Right\n [0, 1, 0], // Top\n [0, -1, 0], // Bottom\n];\n\n/** UV inset constant (imported from constants) */\nconst UV_INSET = UV_EDGE_INSET;\n\n/** Options for box geometry creation */\ninterface BoxGeometryOptions {\n /** Inflation amount (for overlay layers) */\n inflate?: number;\n /** Mirror the geometry along X axis */\n mirrorX?: boolean;\n /** Texture width for UV normalization */\n textureWidth?: number;\n /** Texture height for UV normalization */\n textureHeight?: number;\n /** Use cape UV mapping mode (different u1/u2 assignment) */\n capeUVMode?: boolean;\n}\n\n/**\n * Core function for creating box geometry with various options\n */\nfunction createBoxGeometryCore(\n size: Vec3,\n uv: BoxUV,\n boneIndex: BoneIndex,\n offset: Vec3,\n options: BoxGeometryOptions,\n): BoxGeometry {\n const {\n inflate = 0,\n mirrorX = false,\n textureWidth = 64,\n textureHeight = 64,\n capeUVMode = false,\n } = options;\n\n const hw = size[0] / 2 + inflate;\n const hh = size[1] / 2 + inflate;\n const hd = size[2] / 2 + inflate;\n\n const ox = offset[0];\n const oy = offset[1];\n const oz = offset[2];\n\n // 6 faces, 4 vertices each\n const vertexCount = 24;\n const indexCount = 36;\n\n const vertices = new Float32Array(vertexCount * VERTEX_STRIDE);\n const indices = new Uint16Array(indexCount);\n\n let vertexOffset = 0;\n let indexOffset = 0;\n let baseVertex = 0;\n\n // Mirror factor for X coordinates\n const mx = mirrorX ? -1 : 1;\n\n const addVertex = (\n x: number,\n y: number,\n z: number,\n u: number,\n v: number,\n nx: number,\n ny: number,\n nz: number,\n ) => {\n vertices[vertexOffset++] = x * mx;\n vertices[vertexOffset++] = y;\n vertices[vertexOffset++] = z;\n vertices[vertexOffset++] = u;\n vertices[vertexOffset++] = v;\n vertices[vertexOffset++] = nx * mx;\n vertices[vertexOffset++] = ny;\n vertices[vertexOffset++] = nz;\n vertices[vertexOffset++] = boneIndex;\n vertices[vertexOffset++] = 0; // padding\n };\n\n // When mirrored, reverse winding order to maintain correct face culling\n const addFaceIndices = () => {\n if (mirrorX) {\n indices[indexOffset++] = baseVertex + 2;\n indices[indexOffset++] = baseVertex + 1;\n indices[indexOffset++] = baseVertex;\n indices[indexOffset++] = baseVertex;\n indices[indexOffset++] = baseVertex + 3;\n indices[indexOffset++] = baseVertex + 2;\n } else {\n indices[indexOffset++] = baseVertex;\n indices[indexOffset++] = baseVertex + 1;\n indices[indexOffset++] = baseVertex + 2;\n indices[indexOffset++] = baseVertex + 2;\n indices[indexOffset++] = baseVertex + 3;\n indices[indexOffset++] = baseVertex;\n }\n baseVertex += 4;\n };\n\n // Convert UV from pixel coordinates to 0-1 range\n // Applies UV_INSET towards the center to prevent edge bleeding\n const normalizeUV = (faceUV: {\n u1: number;\n v1: number;\n u2: number;\n v2: number;\n }): [number, number, number, number] => {\n let u1 = faceUV.u1 / textureWidth;\n let u2 = faceUV.u2 / textureWidth;\n let v1 = faceUV.v1 / textureHeight;\n let v2 = faceUV.v2 / textureHeight;\n\n // Inset towards the center of the UV region\n // When u1 < u2 (normal), shrink inward: u1 increases, u2 decreases\n // When u1 > u2 (flipped), shrink inward: u1 decreases, u2 increases\n if (u1 < u2) {\n u1 += UV_INSET;\n u2 -= UV_INSET;\n } else {\n u1 -= UV_INSET;\n u2 += UV_INSET;\n }\n\n if (v1 < v2) {\n v1 += UV_INSET;\n v2 -= UV_INSET;\n } else {\n v1 -= UV_INSET;\n v2 += UV_INSET;\n }\n\n return [u1, v1, u2, v2];\n };\n\n if (capeUVMode) {\n // Cape/Elytra UV mapping mode\n // Front face (+Z)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.front);\n const [nx, ny, nz] = FACE_NORMALS[Face.Front];\n addVertex(ox - hw, oy - hh, oz + hd, u2, v2, nx, ny, nz);\n addVertex(ox + hw, oy - hh, oz + hd, u1, v2, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz + hd, u1, v1, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz + hd, u2, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Back face (-Z)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.back);\n const [nx, ny, nz] = FACE_NORMALS[Face.Back];\n addVertex(ox + hw, oy - hh, oz - hd, u2, v2, nx, ny, nz);\n addVertex(ox - hw, oy - hh, oz - hd, u1, v2, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz - hd, u1, v1, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz - hd, u2, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Left face (-X)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.left);\n const [nx, ny, nz] = FACE_NORMALS[Face.Left];\n addVertex(ox - hw, oy - hh, oz - hd, u2, v2, nx, ny, nz);\n addVertex(ox - hw, oy - hh, oz + hd, u1, v2, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz + hd, u1, v1, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz - hd, u2, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Right face (+X)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.right);\n const [nx, ny, nz] = FACE_NORMALS[Face.Right];\n addVertex(ox + hw, oy - hh, oz + hd, u2, v2, nx, ny, nz);\n addVertex(ox + hw, oy - hh, oz - hd, u1, v2, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz - hd, u1, v1, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz + hd, u2, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Top face (+Y)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.top);\n const [nx, ny, nz] = FACE_NORMALS[Face.Top];\n addVertex(ox - hw, oy + hh, oz + hd, u1, v2, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz + hd, u2, v2, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz - hd, u2, v1, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz - hd, u1, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Bottom face (-Y)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.bottom);\n const [nx, ny, nz] = FACE_NORMALS[Face.Bottom];\n addVertex(ox - hw, oy - hh, oz - hd, u1, v1, nx, ny, nz);\n addVertex(ox + hw, oy - hh, oz - hd, u2, v1, nx, ny, nz);\n addVertex(ox + hw, oy - hh, oz + hd, u2, v2, nx, ny, nz);\n addVertex(ox - hw, oy - hh, oz + hd, u1, v2, nx, ny, nz);\n addFaceIndices();\n }\n } else {\n // Standard skin UV mapping mode\n // Front face (+Z)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.front);\n const [nx, ny, nz] = FACE_NORMALS[Face.Front];\n addVertex(ox - hw, oy - hh, oz + hd, u1, v2, nx, ny, nz);\n addVertex(ox + hw, oy - hh, oz + hd, u2, v2, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz + hd, u2, v1, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz + hd, u1, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Back face (-Z)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.back);\n const [nx, ny, nz] = FACE_NORMALS[Face.Back];\n addVertex(ox + hw, oy - hh, oz - hd, u1, v2, nx, ny, nz);\n addVertex(ox - hw, oy - hh, oz - hd, u2, v2, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz - hd, u2, v1, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz - hd, u1, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Left face (-X) - uses uv.right (character's right side)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.right);\n const [nx, ny, nz] = FACE_NORMALS[Face.Left];\n addVertex(ox - hw, oy - hh, oz - hd, u1, v2, nx, ny, nz);\n addVertex(ox - hw, oy - hh, oz + hd, u2, v2, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz + hd, u2, v1, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz - hd, u1, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Right face (+X) - uses uv.left (character's left side)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.left);\n const [nx, ny, nz] = FACE_NORMALS[Face.Right];\n addVertex(ox + hw, oy - hh, oz + hd, u1, v2, nx, ny, nz);\n addVertex(ox + hw, oy - hh, oz - hd, u2, v2, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz - hd, u2, v1, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz + hd, u1, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Top face (+Y)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.top);\n const [nx, ny, nz] = FACE_NORMALS[Face.Top];\n addVertex(ox - hw, oy + hh, oz + hd, u1, v2, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz + hd, u2, v2, nx, ny, nz);\n addVertex(ox + hw, oy + hh, oz - hd, u2, v1, nx, ny, nz);\n addVertex(ox - hw, oy + hh, oz - hd, u1, v1, nx, ny, nz);\n addFaceIndices();\n }\n\n // Bottom face (-Y)\n {\n const [u1, v1, u2, v2] = normalizeUV(uv.bottom);\n const [nx, ny, nz] = FACE_NORMALS[Face.Bottom];\n addVertex(ox - hw, oy - hh, oz - hd, u1, v1, nx, ny, nz);\n addVertex(ox + hw, oy - hh, oz - hd, u2, v1, nx, ny, nz);\n addVertex(ox + hw, oy - hh, oz + hd, u2, v2, nx, ny, nz);\n addVertex(ox - hw, oy - hh, oz + hd, u1, v2, nx, ny, nz);\n addFaceIndices();\n }\n }\n\n return {\n vertices,\n indices,\n vertexCount,\n indexCount,\n };\n}\n\n/**\n * Create box geometry with UV mapping for skin parts\n *\n * @param size - Box dimensions [width, height, depth]\n * @param uv - UV mapping for each face (in pixels, 64x64 texture)\n * @param boneIndex - Bone index for skeletal animation\n * @param offset - Position offset from bone origin\n * @param inflate - Inflation amount (for overlay layers)\n */\nexport function createBoxGeometry(\n size: Vec3,\n uv: BoxUV,\n boneIndex: BoneIndex,\n offset: Vec3 = [0, 0, 0],\n inflate = 0,\n): BoxGeometry {\n return createBoxGeometryCore(size, uv, boneIndex, offset, {\n inflate,\n textureWidth: SKIN_TEXTURE_WIDTH,\n textureHeight: SKIN_TEXTURE_HEIGHT,\n capeUVMode: false,\n });\n}\n\n/**\n * Create box geometry for cape/elytra with 64x32 texture\n *\n * @param size - Box dimensions [width, height, depth]\n * @param uv - UV mapping for each face (in pixels, 64x32 texture)\n * @param boneIndex - Bone index for skeletal animation\n * @param offset - Position offset from bone origin\n * @param mirrorX - Mirror the geometry along X axis (for right elytra wing)\n */\nexport function createCapeBoxGeometry(\n size: Vec3,\n uv: BoxUV,\n boneIndex: BoneIndex,\n offset: Vec3 = [0, 0, 0],\n mirrorX = false,\n): BoxGeometry {\n return createBoxGeometryCore(size, uv, boneIndex, offset, {\n mirrorX,\n textureWidth: CAPE_TEXTURE_WIDTH,\n textureHeight: CAPE_TEXTURE_HEIGHT,\n capeUVMode: true,\n });\n}\n\n/**\n * Merge multiple box geometries into one\n */\nexport function mergeGeometries(geometries: BoxGeometry[]): BoxGeometry {\n let totalVertices = 0;\n let totalIndices = 0;\n\n for (const geo of geometries) {\n totalVertices += geo.vertexCount;\n totalIndices += geo.indexCount;\n }\n\n const vertices = new Float32Array(totalVertices * VERTEX_STRIDE);\n const indices = new Uint16Array(totalIndices);\n\n let vertexOffset = 0;\n let indexOffset = 0;\n let baseVertex = 0;\n\n for (const geo of geometries) {\n // Copy vertices\n vertices.set(geo.vertices, vertexOffset);\n vertexOffset += geo.vertices.length;\n\n // Copy indices with offset\n for (let i = 0; i < geo.indexCount; i++) {\n indices[indexOffset++] = geo.indices[i] + baseVertex;\n }\n baseVertex += geo.vertexCount;\n }\n\n return {\n vertices,\n indices,\n vertexCount: totalVertices,\n indexCount: totalIndices,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { createBoxGeometry, createCapeBoxGeometry, mergeGeometries } from "./BoxGeometry.mjs";
2
+
3
+ export { };
@@ -0,0 +1,10 @@
1
+ import { BoneIndex, PART_NAMES, VERTEX_STRIDE, createDefaultVisibility } from "./types.mjs";
2
+ import { BONE_OVERLAY_SCALE, CAPE_TEXTURE_HEIGHT, CAPE_TEXTURE_WIDTH, SKIN_TEXTURE_HEIGHT, SKIN_TEXTURE_WIDTH, UV_EDGE_INSET } from "./constants.mjs";
3
+ import { createPlayerSkeleton, resetSkeleton, setBonePositionOffset, setBoneRotation } from "./PlayerModel.mjs";
4
+ import { createBoxUV } from "./uv/common.mjs";
5
+ import { convertOldSkinFormat, getClassicSkinUV, getSkinUV, getSlimSkinUV, isOldSkinFormat } from "./uv/SkinUV.mjs";
6
+ import { createBoxGeometry, createCapeBoxGeometry, mergeGeometries } from "./geometry/BoxGeometry.mjs";
7
+ import { getCapeUV, getElytraUV } from "./uv/CapeUV.mjs";
8
+ import "./geometry/index.mjs";
9
+
10
+ export { };
@@ -0,0 +1,64 @@
1
+ import { Vec3 } from "../core/math/vec3.mjs";
2
+ import { Quat } from "../core/math/quat.mjs";
3
+
4
+ //#region src/model/types.d.ts
5
+ /** Model variant (arm width) */
6
+ type ModelVariant = "classic" | "slim";
7
+ /** Bone index constants */
8
+ declare enum BoneIndex {
9
+ Root = 0,
10
+ Head = 1,
11
+ Body = 2,
12
+ LeftArm = 3,
13
+ RightArm = 4,
14
+ LeftLeg = 5,
15
+ RightLeg = 6,
16
+ HeadOverlay = 7,
17
+ BodyOverlay = 8,
18
+ LeftArmOverlay = 9,
19
+ RightArmOverlay = 10,
20
+ LeftLegOverlay = 11,
21
+ RightLegOverlay = 12,
22
+ Cape = 13,
23
+ LeftWing = 14,
24
+ RightWing = 15
25
+ }
26
+ /** Bone definition */
27
+ interface Bone {
28
+ index: BoneIndex;
29
+ name: string;
30
+ parentIndex: BoneIndex | null;
31
+ position: Vec3;
32
+ pivot: Vec3;
33
+ rotation: Quat;
34
+ positionOffset: Vec3;
35
+ size: Vec3;
36
+ }
37
+ /** Player skeleton with all bones */
38
+ interface PlayerSkeleton {
39
+ variant: ModelVariant;
40
+ bones: Map<BoneIndex, Bone>;
41
+ }
42
+ /** Part name type */
43
+ type PartName = "head" | "body" | "leftArm" | "rightArm" | "leftLeg" | "rightLeg";
44
+ /** Layer visibility for a single part */
45
+ interface LayerVisibility {
46
+ inner: boolean;
47
+ outer: boolean;
48
+ }
49
+ /** Visibility settings for all skin parts */
50
+ interface PartsVisibility {
51
+ head: LayerVisibility;
52
+ body: LayerVisibility;
53
+ leftArm: LayerVisibility;
54
+ rightArm: LayerVisibility;
55
+ leftLeg: LayerVisibility;
56
+ rightLeg: LayerVisibility;
57
+ }
58
+ /** All part names */
59
+ declare const PART_NAMES: PartName[];
60
+ /** Create default visibility (all visible) */
61
+ declare function createDefaultVisibility(): PartsVisibility;
62
+ //#endregion
63
+ export { BoneIndex, LayerVisibility, ModelVariant, PART_NAMES, PartName, PartsVisibility, PlayerSkeleton, createDefaultVisibility };
64
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/model/types.ts"],"mappings":";;;;AAOA;AAAA,KAAY,YAAA;;aAGA,SAAA;EACV,IAAA;EACA,IAAA;EACA,IAAA;EACA,OAAA;EACA,QAAA;EACA,OAAA;EACA,QAAA;EAEA,WAAA;EACA,WAAA;EACA,cAAA;EACA,eAAA;EACA,cAAA;EACA,eAAA;EAEA,IAAA;EACA,QAAA;EACA,SAAA;AAAA;;UAIe,IAAA;EACf,KAAA,EAAO,SAAA;EACP,IAAA;EACA,WAAA,EAAa,SAAA;EACb,QAAA,EAAU,IAAA;EACV,KAAA,EAAO,IAAA;EACP,QAAA,EAAU,IAAA;EACV,cAAA,EAAgB,IAAA;EAChB,IAAA,EAAM,IAAA;AAAA;;UAIS,cAAA;EACf,OAAA,EAAS,YAAA;EACT,KAAA,EAAO,GAAA,CAAI,SAAA,EAAW,IAAA;AAAA;;KA8CZ,QAAA;;UAGK,eAAA;EACf,KAAA;EACA,KAAA;AAAA;;UAyBe,eAAA;EACf,IAAA,EAAM,eAAA;EACN,IAAA,EAAM,eAAA;EACN,OAAA,EAAS,eAAA;EACT,QAAA,EAAU,eAAA;EACV,OAAA,EAAS,eAAA;EACT,QAAA,EAAU,eAAA;AAAA;;cAIC,UAAA,EAAY,QAAA;;iBAUT,uBAAA,CAAA,GAA2B,eAAA"}
@@ -0,0 +1,67 @@
1
+ import "./bone-utils.mjs";
2
+
3
+ //#region src/model/types.ts
4
+ /** Bone index constants */
5
+ let BoneIndex = /* @__PURE__ */ function(BoneIndex) {
6
+ BoneIndex[BoneIndex["Root"] = 0] = "Root";
7
+ BoneIndex[BoneIndex["Head"] = 1] = "Head";
8
+ BoneIndex[BoneIndex["Body"] = 2] = "Body";
9
+ BoneIndex[BoneIndex["LeftArm"] = 3] = "LeftArm";
10
+ BoneIndex[BoneIndex["RightArm"] = 4] = "RightArm";
11
+ BoneIndex[BoneIndex["LeftLeg"] = 5] = "LeftLeg";
12
+ BoneIndex[BoneIndex["RightLeg"] = 6] = "RightLeg";
13
+ BoneIndex[BoneIndex["HeadOverlay"] = 7] = "HeadOverlay";
14
+ BoneIndex[BoneIndex["BodyOverlay"] = 8] = "BodyOverlay";
15
+ BoneIndex[BoneIndex["LeftArmOverlay"] = 9] = "LeftArmOverlay";
16
+ BoneIndex[BoneIndex["RightArmOverlay"] = 10] = "RightArmOverlay";
17
+ BoneIndex[BoneIndex["LeftLegOverlay"] = 11] = "LeftLegOverlay";
18
+ BoneIndex[BoneIndex["RightLegOverlay"] = 12] = "RightLegOverlay";
19
+ BoneIndex[BoneIndex["Cape"] = 13] = "Cape";
20
+ BoneIndex[BoneIndex["LeftWing"] = 14] = "LeftWing";
21
+ BoneIndex[BoneIndex["RightWing"] = 15] = "RightWing";
22
+ return BoneIndex;
23
+ }({});
24
+ /** All part names */
25
+ const PART_NAMES = [
26
+ "head",
27
+ "body",
28
+ "leftArm",
29
+ "rightArm",
30
+ "leftLeg",
31
+ "rightLeg"
32
+ ];
33
+ /** Create default visibility (all visible) */
34
+ function createDefaultVisibility() {
35
+ return {
36
+ head: {
37
+ inner: true,
38
+ outer: true
39
+ },
40
+ body: {
41
+ inner: true,
42
+ outer: true
43
+ },
44
+ leftArm: {
45
+ inner: true,
46
+ outer: true
47
+ },
48
+ rightArm: {
49
+ inner: true,
50
+ outer: true
51
+ },
52
+ leftLeg: {
53
+ inner: true,
54
+ outer: true
55
+ },
56
+ rightLeg: {
57
+ inner: true,
58
+ outer: true
59
+ }
60
+ };
61
+ }
62
+ /** Vertex data stride (floats per vertex) */
63
+ const VERTEX_STRIDE = 10;
64
+
65
+ //#endregion
66
+ export { BoneIndex, PART_NAMES, VERTEX_STRIDE, createDefaultVisibility };
67
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.mjs","names":[],"sources":["../../src/model/types.ts"],"sourcesContent":["/**\n * Model system types\n */\n\nimport type { Quat, Vec3 } from \"../core/math\";\n\n/** Model variant (arm width) */\nexport type ModelVariant = \"classic\" | \"slim\";\n\n/** Bone index constants */\nexport enum BoneIndex {\n Root = 0,\n Head = 1,\n Body = 2,\n LeftArm = 3,\n RightArm = 4,\n LeftLeg = 5,\n RightLeg = 6,\n // Overlay layers (same transform as parent)\n HeadOverlay = 7,\n BodyOverlay = 8,\n LeftArmOverlay = 9,\n RightArmOverlay = 10,\n LeftLegOverlay = 11,\n RightLegOverlay = 12,\n // Cape and elytra\n Cape = 13,\n LeftWing = 14,\n RightWing = 15,\n}\n\n/** Bone definition */\nexport interface Bone {\n index: BoneIndex;\n name: string;\n parentIndex: BoneIndex | null;\n position: Vec3; // Local position relative to parent\n pivot: Vec3; // Pivot point for rotation\n rotation: Quat; // Current rotation\n positionOffset: Vec3; // Animation-driven position offset\n size: Vec3; // Size of the associated geometry\n}\n\n/** Player skeleton with all bones */\nexport interface PlayerSkeleton {\n variant: ModelVariant;\n bones: Map<BoneIndex, Bone>;\n}\n\n/** Box geometry data */\nexport interface BoxGeometry {\n vertices: Float32Array; // position + uv + normal + boneIndex\n indices: Uint16Array;\n vertexCount: number;\n indexCount: number;\n}\n\n/** UV coordinates for a face */\nexport interface FaceUV {\n u1: number; // Left U (0-64)\n v1: number; // Top V (0-64)\n u2: number; // Right U (0-64)\n v2: number; // Bottom V (0-64)\n}\n\n/** UV mapping for a box (6 faces) */\nexport interface BoxUV {\n front: FaceUV;\n back: FaceUV;\n left: FaceUV;\n right: FaceUV;\n top: FaceUV;\n bottom: FaceUV;\n}\n\n/** Part UV mapping with inner and outer layer */\nexport interface PartUV {\n inner: BoxUV;\n outer: BoxUV;\n}\n\n/** Complete skin UV mapping */\nexport interface SkinUVMap {\n head: PartUV;\n body: PartUV;\n leftArm: PartUV;\n rightArm: PartUV;\n leftLeg: PartUV;\n rightLeg: PartUV;\n}\n\n/** Part name type */\nexport type PartName = \"head\" | \"body\" | \"leftArm\" | \"rightArm\" | \"leftLeg\" | \"rightLeg\";\n\n/** Layer visibility for a single part */\nexport interface LayerVisibility {\n inner: boolean;\n outer: boolean;\n}\n\n/** Layer mask for quick visibility checks (internal use) */\nexport enum LayerMask {\n None = 0,\n Inner = 1 << 0,\n Outer = 1 << 1,\n Both = Inner | Outer,\n}\n\n/** Convert LayerVisibility to LayerMask */\nexport function visibilityToMask(visibility: LayerVisibility): LayerMask {\n return (visibility.inner ? LayerMask.Inner : 0) | (visibility.outer ? LayerMask.Outer : 0);\n}\n\n/** Convert LayerMask to LayerVisibility */\nexport function maskToVisibility(mask: LayerMask): LayerVisibility {\n return {\n inner: (mask & LayerMask.Inner) !== 0,\n outer: (mask & LayerMask.Outer) !== 0,\n };\n}\n\n/** Visibility settings for all skin parts */\nexport interface PartsVisibility {\n head: LayerVisibility;\n body: LayerVisibility;\n leftArm: LayerVisibility;\n rightArm: LayerVisibility;\n leftLeg: LayerVisibility;\n rightLeg: LayerVisibility;\n}\n\n/** All part names */\nexport const PART_NAMES: PartName[] = [\n \"head\",\n \"body\",\n \"leftArm\",\n \"rightArm\",\n \"leftLeg\",\n \"rightLeg\",\n];\n\n/** Create default visibility (all visible) */\nexport function createDefaultVisibility(): PartsVisibility {\n return {\n head: { inner: true, outer: true },\n body: { inner: true, outer: true },\n leftArm: { inner: true, outer: true },\n rightArm: { inner: true, outer: true },\n leftLeg: { inner: true, outer: true },\n rightLeg: { inner: true, outer: true },\n };\n}\n\n/** Vertex data stride (floats per vertex) */\nexport const VERTEX_STRIDE = 10; // 3 pos + 2 uv + 3 normal + 1 boneIndex + 1 padding\n\n// Re-export getBoneLocalMatrix from bone-utils to maintain backwards compatibility\n// This avoids circular dependency between model/types and core/math\nexport { getBoneLocalMatrix } from \"./bone-utils\";\n"],"mappings":";;;;AAUA,IAAY,gDAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;AAwGF,MAAa,aAAyB;CACpC;CACA;CACA;CACA;CACA;CACA;CACD;;AAGD,SAAgB,0BAA2C;AACzD,QAAO;EACL,MAAM;GAAE,OAAO;GAAM,OAAO;GAAM;EAClC,MAAM;GAAE,OAAO;GAAM,OAAO;GAAM;EAClC,SAAS;GAAE,OAAO;GAAM,OAAO;GAAM;EACrC,UAAU;GAAE,OAAO;GAAM,OAAO;GAAM;EACtC,SAAS;GAAE,OAAO;GAAM,OAAO;GAAM;EACrC,UAAU;GAAE,OAAO;GAAM,OAAO;GAAM;EACvC;;;AAIH,MAAa,gBAAgB"}
@@ -0,0 +1,25 @@
1
+ import { CAPE_TEXTURE_HEIGHT, CAPE_TEXTURE_WIDTH } from "../constants.mjs";
2
+ import { createBoxUV } from "./common.mjs";
3
+
4
+ //#region src/model/uv/CapeUV.ts
5
+ /**
6
+ * Get UV mapping for cape
7
+ * Cape geometry: 10 wide, 16 tall, 1 deep
8
+ * UV starts at (0, 0) in the 64x32 texture
9
+ */
10
+ function getCapeUV() {
11
+ return createBoxUV(0, 0, 10, 16, 1, "cape");
12
+ }
13
+ /**
14
+ * Get UV mapping for elytra wing
15
+ * UV dimensions: 10 wide, 20 tall, 2 deep (texture layout)
16
+ * UV starts at (22, 0) in the 64x32 texture
17
+ * Both wings use the same UV (right wing is mirrored via geometry)
18
+ */
19
+ function getElytraUV() {
20
+ return createBoxUV(22, 0, 10, 20, 2, "elytra");
21
+ }
22
+
23
+ //#endregion
24
+ export { getCapeUV, getElytraUV };
25
+ //# sourceMappingURL=CapeUV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CapeUV.mjs","names":[],"sources":["../../../src/model/uv/CapeUV.ts"],"sourcesContent":["/**\n * Minecraft cape and elytra UV coordinates (64x32 format)\n *\n * Cape texture layout (64x32):\n * - Cape: starts at (0, 0), size 10x16x1\n * - Elytra: starts at (22, 0), size 10x20x2\n *\n * Reference: skinview3d implementation and Minecraft wiki\n */\n\nimport type { BoxUV } from \"../types\";\nimport { createBoxUV } from \"./common\";\n\n// Re-export for backward compatibility\nexport { CAPE_TEXTURE_WIDTH, CAPE_TEXTURE_HEIGHT } from \"../constants\";\n\n/**\n * Get UV mapping for cape\n * Cape geometry: 10 wide, 16 tall, 1 deep\n * UV starts at (0, 0) in the 64x32 texture\n */\nexport function getCapeUV(): BoxUV {\n return createBoxUV(0, 0, 10, 16, 1, \"cape\");\n}\n\n/**\n * Get UV mapping for elytra wing\n * UV dimensions: 10 wide, 20 tall, 2 deep (texture layout)\n * UV starts at (22, 0) in the 64x32 texture\n * Both wings use the same UV (right wing is mirrored via geometry)\n */\nexport function getElytraUV(): BoxUV {\n return createBoxUV(22, 0, 10, 20, 2, \"elytra\");\n}\n"],"mappings":";;;;;;;;;AAqBA,SAAgB,YAAmB;AACjC,QAAO,YAAY,GAAG,GAAG,IAAI,IAAI,GAAG,OAAO;;;;;;;;AAS7C,SAAgB,cAAqB;AACnC,QAAO,YAAY,IAAI,GAAG,IAAI,IAAI,GAAG,SAAS"}
@@ -0,0 +1,104 @@
1
+ import { createBoxUV } from "./common.mjs";
2
+
3
+ //#region src/model/uv/SkinUV.ts
4
+ /**
5
+ * Get UV mapping for classic (4-pixel wide arms) model
6
+ */
7
+ function getClassicSkinUV() {
8
+ return {
9
+ head: {
10
+ inner: createBoxUV(0, 0, 8, 8, 8),
11
+ outer: createBoxUV(32, 0, 8, 8, 8)
12
+ },
13
+ body: {
14
+ inner: createBoxUV(16, 16, 8, 12, 4),
15
+ outer: createBoxUV(16, 32, 8, 12, 4)
16
+ },
17
+ rightArm: {
18
+ inner: createBoxUV(40, 16, 4, 12, 4),
19
+ outer: createBoxUV(40, 32, 4, 12, 4)
20
+ },
21
+ leftArm: {
22
+ inner: createBoxUV(32, 48, 4, 12, 4),
23
+ outer: createBoxUV(48, 48, 4, 12, 4)
24
+ },
25
+ rightLeg: {
26
+ inner: createBoxUV(0, 16, 4, 12, 4),
27
+ outer: createBoxUV(0, 32, 4, 12, 4)
28
+ },
29
+ leftLeg: {
30
+ inner: createBoxUV(16, 48, 4, 12, 4),
31
+ outer: createBoxUV(0, 48, 4, 12, 4)
32
+ }
33
+ };
34
+ }
35
+ /**
36
+ * Get UV mapping for slim (3-pixel wide arms) model
37
+ */
38
+ function getSlimSkinUV() {
39
+ const classic = getClassicSkinUV();
40
+ return {
41
+ head: classic.head,
42
+ body: classic.body,
43
+ rightLeg: classic.rightLeg,
44
+ leftLeg: classic.leftLeg,
45
+ rightArm: {
46
+ inner: createBoxUV(40, 16, 3, 12, 4),
47
+ outer: createBoxUV(40, 32, 3, 12, 4)
48
+ },
49
+ leftArm: {
50
+ inner: createBoxUV(32, 48, 3, 12, 4),
51
+ outer: createBoxUV(48, 48, 3, 12, 4)
52
+ }
53
+ };
54
+ }
55
+ /**
56
+ * Get UV mapping based on model variant
57
+ */
58
+ function getSkinUV(variant) {
59
+ return variant === "slim" ? getSlimSkinUV() : getClassicSkinUV();
60
+ }
61
+ /**
62
+ * Check if skin is old format (64x32) or new format (64x64)
63
+ */
64
+ function isOldSkinFormat(width, height) {
65
+ return width === 64 && height === 32;
66
+ }
67
+ /**
68
+ * Convert old 64x32 skin to 64x64 format
69
+ * The old format only has right arm/leg textures, which are mirrored for left
70
+ */
71
+ function convertOldSkinFormat(imageData) {
72
+ if (imageData.height === 64) return imageData;
73
+ const newData = new ImageData(64, 64);
74
+ const src = imageData.data;
75
+ const dst = newData.data;
76
+ for (let y = 0; y < 32; y++) for (let x = 0; x < 64; x++) {
77
+ const srcIdx = (y * 64 + x) * 4;
78
+ const dstIdx = (y * 64 + x) * 4;
79
+ dst[dstIdx] = src[srcIdx];
80
+ dst[dstIdx + 1] = src[srcIdx + 1];
81
+ dst[dstIdx + 2] = src[srcIdx + 2];
82
+ dst[dstIdx + 3] = src[srcIdx + 3];
83
+ }
84
+ copyAndMirror(src, dst, 64, 40, 16, 32, 48, 16, 16);
85
+ copyAndMirror(src, dst, 64, 0, 16, 16, 48, 16, 16);
86
+ return newData;
87
+ }
88
+ /**
89
+ * Copy and horizontally mirror a region
90
+ */
91
+ function copyAndMirror(src, dst, width, srcX, srcY, dstX, dstY, regionW, regionH) {
92
+ for (let y = 0; y < regionH; y++) for (let x = 0; x < regionW; x++) {
93
+ const srcIdx = ((srcY + y) * width + (srcX + regionW - 1 - x)) * 4;
94
+ const dstIdx = ((dstY + y) * width + (dstX + x)) * 4;
95
+ dst[dstIdx] = src[srcIdx];
96
+ dst[dstIdx + 1] = src[srcIdx + 1];
97
+ dst[dstIdx + 2] = src[srcIdx + 2];
98
+ dst[dstIdx + 3] = src[srcIdx + 3];
99
+ }
100
+ }
101
+
102
+ //#endregion
103
+ export { convertOldSkinFormat, getClassicSkinUV, getSkinUV, getSlimSkinUV, isOldSkinFormat };
104
+ //# sourceMappingURL=SkinUV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkinUV.mjs","names":[],"sources":["../../../src/model/uv/SkinUV.ts"],"sourcesContent":["/**\n * Minecraft skin UV coordinates (64x64 format)\n *\n * Reference: https://minecraft.wiki/w/Skin\n * The skin texture is laid out in a specific pattern where each body part\n * has designated regions for both the inner layer and outer (overlay) layer.\n */\n\nimport type { ModelVariant, SkinUVMap } from \"../types\";\nimport { createBoxUV } from \"./common\";\n\n/**\n * Get UV mapping for classic (4-pixel wide arms) model\n */\nexport function getClassicSkinUV(): SkinUVMap {\n return {\n // Head: 8x8x8, starts at (0, 0)\n head: {\n inner: createBoxUV(0, 0, 8, 8, 8),\n outer: createBoxUV(32, 0, 8, 8, 8),\n },\n\n // Body: 8x12x4, starts at (16, 16)\n body: {\n inner: createBoxUV(16, 16, 8, 12, 4),\n outer: createBoxUV(16, 32, 8, 12, 4),\n },\n\n // Right Arm: 4x12x4, starts at (40, 16)\n rightArm: {\n inner: createBoxUV(40, 16, 4, 12, 4),\n outer: createBoxUV(40, 32, 4, 12, 4),\n },\n\n // Left Arm: 4x12x4, starts at (32, 48)\n leftArm: {\n inner: createBoxUV(32, 48, 4, 12, 4),\n outer: createBoxUV(48, 48, 4, 12, 4),\n },\n\n // Right Leg: 4x12x4, starts at (0, 16)\n rightLeg: {\n inner: createBoxUV(0, 16, 4, 12, 4),\n outer: createBoxUV(0, 32, 4, 12, 4),\n },\n\n // Left Leg: 4x12x4, starts at (16, 48)\n leftLeg: {\n inner: createBoxUV(16, 48, 4, 12, 4),\n outer: createBoxUV(0, 48, 4, 12, 4),\n },\n };\n}\n\n/**\n * Get UV mapping for slim (3-pixel wide arms) model\n */\nexport function getSlimSkinUV(): SkinUVMap {\n const classic = getClassicSkinUV();\n\n return {\n head: classic.head,\n body: classic.body,\n rightLeg: classic.rightLeg,\n leftLeg: classic.leftLeg,\n\n // Right Arm: 3x12x4, starts at (40, 16)\n rightArm: {\n inner: createBoxUV(40, 16, 3, 12, 4),\n outer: createBoxUV(40, 32, 3, 12, 4),\n },\n\n // Left Arm: 3x12x4, starts at (32, 48)\n leftArm: {\n inner: createBoxUV(32, 48, 3, 12, 4),\n outer: createBoxUV(48, 48, 3, 12, 4),\n },\n };\n}\n\n/**\n * Get UV mapping based on model variant\n */\nexport function getSkinUV(variant: ModelVariant): SkinUVMap {\n return variant === \"slim\" ? getSlimSkinUV() : getClassicSkinUV();\n}\n\n/**\n * Check if skin is old format (64x32) or new format (64x64)\n */\nexport function isOldSkinFormat(width: number, height: number): boolean {\n return width === 64 && height === 32;\n}\n\n/**\n * Convert old 64x32 skin to 64x64 format\n * The old format only has right arm/leg textures, which are mirrored for left\n */\nexport function convertOldSkinFormat(imageData: ImageData): ImageData {\n if (imageData.height === 64) {\n return imageData; // Already new format\n }\n\n // Create new 64x64 image\n const newData = new ImageData(64, 64);\n const src = imageData.data;\n const dst = newData.data;\n\n // Copy top half (0-31) as-is\n for (let y = 0; y < 32; y++) {\n for (let x = 0; x < 64; x++) {\n const srcIdx = (y * 64 + x) * 4;\n const dstIdx = (y * 64 + x) * 4;\n dst[dstIdx] = src[srcIdx];\n dst[dstIdx + 1] = src[srcIdx + 1];\n dst[dstIdx + 2] = src[srcIdx + 2];\n dst[dstIdx + 3] = src[srcIdx + 3];\n }\n }\n\n // Mirror right arm to left arm position (32, 48)\n // Right arm is at (40, 16) with size 4x12x4\n copyAndMirror(src, dst, 64, 40, 16, 32, 48, 16, 16);\n\n // Mirror right leg to left leg position (16, 48)\n // Right leg is at (0, 16) with size 4x12x4\n copyAndMirror(src, dst, 64, 0, 16, 16, 48, 16, 16);\n\n return newData;\n}\n\n/**\n * Copy and horizontally mirror a region\n */\nfunction copyAndMirror(\n src: Uint8ClampedArray,\n dst: Uint8ClampedArray,\n width: number,\n srcX: number,\n srcY: number,\n dstX: number,\n dstY: number,\n regionW: number,\n regionH: number,\n): void {\n for (let y = 0; y < regionH; y++) {\n for (let x = 0; x < regionW; x++) {\n const srcIdx = ((srcY + y) * width + (srcX + regionW - 1 - x)) * 4;\n const dstIdx = ((dstY + y) * width + (dstX + x)) * 4;\n dst[dstIdx] = src[srcIdx];\n dst[dstIdx + 1] = src[srcIdx + 1];\n dst[dstIdx + 2] = src[srcIdx + 2];\n dst[dstIdx + 3] = src[srcIdx + 3];\n }\n }\n}\n"],"mappings":";;;;;;AAcA,SAAgB,mBAA8B;AAC5C,QAAO;EAEL,MAAM;GACJ,OAAO,YAAY,GAAG,GAAG,GAAG,GAAG,EAAE;GACjC,OAAO,YAAY,IAAI,GAAG,GAAG,GAAG,EAAE;GACnC;EAGD,MAAM;GACJ,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACpC,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACrC;EAGD,UAAU;GACR,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACpC,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACrC;EAGD,SAAS;GACP,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACpC,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACrC;EAGD,UAAU;GACR,OAAO,YAAY,GAAG,IAAI,GAAG,IAAI,EAAE;GACnC,OAAO,YAAY,GAAG,IAAI,GAAG,IAAI,EAAE;GACpC;EAGD,SAAS;GACP,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACpC,OAAO,YAAY,GAAG,IAAI,GAAG,IAAI,EAAE;GACpC;EACF;;;;;AAMH,SAAgB,gBAA2B;CACzC,MAAM,UAAU,kBAAkB;AAElC,QAAO;EACL,MAAM,QAAQ;EACd,MAAM,QAAQ;EACd,UAAU,QAAQ;EAClB,SAAS,QAAQ;EAGjB,UAAU;GACR,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACpC,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACrC;EAGD,SAAS;GACP,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACpC,OAAO,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE;GACrC;EACF;;;;;AAMH,SAAgB,UAAU,SAAkC;AAC1D,QAAO,YAAY,SAAS,eAAe,GAAG,kBAAkB;;;;;AAMlE,SAAgB,gBAAgB,OAAe,QAAyB;AACtE,QAAO,UAAU,MAAM,WAAW;;;;;;AAOpC,SAAgB,qBAAqB,WAAiC;AACpE,KAAI,UAAU,WAAW,GACvB,QAAO;CAIT,MAAM,UAAU,IAAI,UAAU,IAAI,GAAG;CACrC,MAAM,MAAM,UAAU;CACtB,MAAM,MAAM,QAAQ;AAGpB,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,IACtB,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,UAAU,IAAI,KAAK,KAAK;EAC9B,MAAM,UAAU,IAAI,KAAK,KAAK;AAC9B,MAAI,UAAU,IAAI;AAClB,MAAI,SAAS,KAAK,IAAI,SAAS;AAC/B,MAAI,SAAS,KAAK,IAAI,SAAS;AAC/B,MAAI,SAAS,KAAK,IAAI,SAAS;;AAMnC,eAAc,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAInD,eAAc,KAAK,KAAK,IAAI,GAAG,IAAI,IAAI,IAAI,IAAI,GAAG;AAElD,QAAO;;;;;AAMT,SAAS,cACP,KACA,KACA,OACA,MACA,MACA,MACA,MACA,SACA,SACM;AACN,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,IAC3B,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,KAAK;EAChC,MAAM,WAAW,OAAO,KAAK,SAAS,OAAO,UAAU,IAAI,MAAM;EACjE,MAAM,WAAW,OAAO,KAAK,SAAS,OAAO,MAAM;AACnD,MAAI,UAAU,IAAI;AAClB,MAAI,SAAS,KAAK,IAAI,SAAS;AAC/B,MAAI,SAAS,KAAK,IAAI,SAAS;AAC/B,MAAI,SAAS,KAAK,IAAI,SAAS"}
@@ -0,0 +1,147 @@
1
+ //#region src/model/uv/common.ts
2
+ /**
3
+ * Create BoxUV from top-left corner and dimensions
4
+ *
5
+ * Standard Minecraft UV layout (right to left, then down):
6
+ * - Row 1: right side, front, left side, back
7
+ * - Row 0: top (above front), bottom (above back area)
8
+ *
9
+ * @param x - Top-left X coordinate in texture
10
+ * @param y - Top-left Y coordinate in texture
11
+ * @param width - Width of the box (front/back face width)
12
+ * @param height - Height of the box
13
+ * @param depth - Depth of the box (side face width)
14
+ * @param layout - UV layout type (default: "standard")
15
+ */
16
+ function createBoxUV(x, y, width, height, depth, layout = "standard") {
17
+ const rightU1 = x;
18
+ const rightU2 = x + depth;
19
+ const frontU1 = x + depth;
20
+ const frontU2 = x + depth + width;
21
+ const leftU1 = x + depth + width;
22
+ const leftU2 = x + depth + width + depth;
23
+ const backU1 = x + depth + width + depth;
24
+ const backU2 = x + depth + width + depth + width;
25
+ const sideV1 = y + depth;
26
+ const sideV2 = y + depth + height;
27
+ const topV1 = y;
28
+ const topV2 = y + depth;
29
+ if (layout === "cape") return {
30
+ right: {
31
+ u1: rightU1,
32
+ v1: sideV1,
33
+ u2: rightU2,
34
+ v2: sideV2
35
+ },
36
+ front: {
37
+ u1: backU1,
38
+ v1: sideV1,
39
+ u2: backU2,
40
+ v2: sideV2
41
+ },
42
+ left: {
43
+ u1: leftU1,
44
+ v1: sideV1,
45
+ u2: leftU2,
46
+ v2: sideV2
47
+ },
48
+ back: {
49
+ u1: frontU1,
50
+ v1: sideV1,
51
+ u2: frontU2,
52
+ v2: sideV2
53
+ },
54
+ top: {
55
+ u1: frontU1,
56
+ v1: topV1,
57
+ u2: frontU2,
58
+ v2: topV2
59
+ },
60
+ bottom: {
61
+ u1: leftU1,
62
+ v1: topV1,
63
+ u2: leftU1 + width,
64
+ v2: topV2
65
+ }
66
+ };
67
+ if (layout === "elytra") return {
68
+ left: {
69
+ u1: rightU2,
70
+ v1: sideV1,
71
+ u2: rightU1,
72
+ v2: sideV2
73
+ },
74
+ front: {
75
+ u1: frontU2,
76
+ v1: sideV1,
77
+ u2: frontU1,
78
+ v2: sideV2
79
+ },
80
+ right: {
81
+ u1: leftU2,
82
+ v1: sideV1,
83
+ u2: leftU1,
84
+ v2: sideV2
85
+ },
86
+ back: {
87
+ u1: backU2,
88
+ v1: sideV1,
89
+ u2: backU1,
90
+ v2: sideV2
91
+ },
92
+ top: {
93
+ u1: frontU1,
94
+ v1: topV1,
95
+ u2: frontU2,
96
+ v2: topV2
97
+ },
98
+ bottom: {
99
+ u1: leftU1,
100
+ v1: topV1,
101
+ u2: leftU1 + width,
102
+ v2: topV2
103
+ }
104
+ };
105
+ return {
106
+ right: {
107
+ u1: rightU1,
108
+ v1: sideV1,
109
+ u2: rightU2,
110
+ v2: sideV2
111
+ },
112
+ front: {
113
+ u1: frontU1,
114
+ v1: sideV1,
115
+ u2: frontU2,
116
+ v2: sideV2
117
+ },
118
+ left: {
119
+ u1: leftU1,
120
+ v1: sideV1,
121
+ u2: leftU2,
122
+ v2: sideV2
123
+ },
124
+ back: {
125
+ u1: backU1,
126
+ v1: sideV1,
127
+ u2: backU2,
128
+ v2: sideV2
129
+ },
130
+ top: {
131
+ u1: frontU1,
132
+ v1: topV1,
133
+ u2: frontU2,
134
+ v2: topV2
135
+ },
136
+ bottom: {
137
+ u1: leftU1,
138
+ v1: topV1,
139
+ u2: leftU1 + width,
140
+ v2: topV2
141
+ }
142
+ };
143
+ }
144
+
145
+ //#endregion
146
+ export { createBoxUV };
147
+ //# sourceMappingURL=common.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.mjs","names":[],"sources":["../../../src/model/uv/common.ts"],"sourcesContent":["/**\n * Common UV mapping utilities\n *\n * Provides a unified box UV creation function that supports different\n * texture layouts (skin, cape, elytra) through configuration options.\n */\n\nimport type { BoxUV } from \"../types\";\n\n/** UV layout type for different texture conventions */\nexport type UVLayout =\n | \"standard\" // Skin layout: right, front, left, back\n | \"cape\" // Cape layout: front/back swapped for correct facing\n | \"elytra\"; // Elytra layout: u1/u2 swapped for side faces\n\n/**\n * Create BoxUV from top-left corner and dimensions\n *\n * Standard Minecraft UV layout (right to left, then down):\n * - Row 1: right side, front, left side, back\n * - Row 0: top (above front), bottom (above back area)\n *\n * @param x - Top-left X coordinate in texture\n * @param y - Top-left Y coordinate in texture\n * @param width - Width of the box (front/back face width)\n * @param height - Height of the box\n * @param depth - Depth of the box (side face width)\n * @param layout - UV layout type (default: \"standard\")\n */\nexport function createBoxUV(\n x: number,\n y: number,\n width: number,\n height: number,\n depth: number,\n layout: UVLayout = \"standard\",\n): BoxUV {\n // Calculate base UV coordinates\n const rightU1 = x;\n const rightU2 = x + depth;\n const frontU1 = x + depth;\n const frontU2 = x + depth + width;\n const leftU1 = x + depth + width;\n const leftU2 = x + depth + width + depth;\n const backU1 = x + depth + width + depth;\n const backU2 = x + depth + width + depth + width;\n\n const sideV1 = y + depth;\n const sideV2 = y + depth + height;\n const topV1 = y;\n const topV2 = y + depth;\n\n if (layout === \"cape\") {\n // Cape: swap front/back for correct texture facing\n return {\n right: { u1: rightU1, v1: sideV1, u2: rightU2, v2: sideV2 },\n front: { u1: backU1, v1: sideV1, u2: backU2, v2: sideV2 },\n left: { u1: leftU1, v1: sideV1, u2: leftU2, v2: sideV2 },\n back: { u1: frontU1, v1: sideV1, u2: frontU2, v2: sideV2 },\n top: { u1: frontU1, v1: topV1, u2: frontU2, v2: topV2 },\n bottom: { u1: leftU1, v1: topV1, u2: leftU1 + width, v2: topV2 },\n };\n }\n\n if (layout === \"elytra\") {\n // Elytra: swap u1/u2 for side faces to match skinview3d's setUVs behavior\n // This compensates for createCapeBoxGeometry using u1 for right side and u2 for left side\n return {\n left: { u1: rightU2, v1: sideV1, u2: rightU1, v2: sideV2 },\n front: { u1: frontU2, v1: sideV1, u2: frontU1, v2: sideV2 },\n right: { u1: leftU2, v1: sideV1, u2: leftU1, v2: sideV2 },\n back: { u1: backU2, v1: sideV1, u2: backU1, v2: sideV2 },\n top: { u1: frontU1, v1: topV1, u2: frontU2, v2: topV2 },\n bottom: { u1: leftU1, v1: topV1, u2: leftU1 + width, v2: topV2 },\n };\n }\n\n // Standard skin layout\n return {\n right: { u1: rightU1, v1: sideV1, u2: rightU2, v2: sideV2 },\n front: { u1: frontU1, v1: sideV1, u2: frontU2, v2: sideV2 },\n left: { u1: leftU1, v1: sideV1, u2: leftU2, v2: sideV2 },\n back: { u1: backU1, v1: sideV1, u2: backU2, v2: sideV2 },\n top: { u1: frontU1, v1: topV1, u2: frontU2, v2: topV2 },\n bottom: { u1: leftU1, v1: topV1, u2: leftU1 + width, v2: topV2 },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AA6BA,SAAgB,YACd,GACA,GACA,OACA,QACA,OACA,SAAmB,YACZ;CAEP,MAAM,UAAU;CAChB,MAAM,UAAU,IAAI;CACpB,MAAM,UAAU,IAAI;CACpB,MAAM,UAAU,IAAI,QAAQ;CAC5B,MAAM,SAAS,IAAI,QAAQ;CAC3B,MAAM,SAAS,IAAI,QAAQ,QAAQ;CACnC,MAAM,SAAS,IAAI,QAAQ,QAAQ;CACnC,MAAM,SAAS,IAAI,QAAQ,QAAQ,QAAQ;CAE3C,MAAM,SAAS,IAAI;CACnB,MAAM,SAAS,IAAI,QAAQ;CAC3B,MAAM,QAAQ;CACd,MAAM,QAAQ,IAAI;AAElB,KAAI,WAAW,OAEb,QAAO;EACL,OAAO;GAAE,IAAI;GAAS,IAAI;GAAQ,IAAI;GAAS,IAAI;GAAQ;EAC3D,OAAO;GAAE,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ;EACzD,MAAM;GAAE,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ;EACxD,MAAM;GAAE,IAAI;GAAS,IAAI;GAAQ,IAAI;GAAS,IAAI;GAAQ;EAC1D,KAAK;GAAE,IAAI;GAAS,IAAI;GAAO,IAAI;GAAS,IAAI;GAAO;EACvD,QAAQ;GAAE,IAAI;GAAQ,IAAI;GAAO,IAAI,SAAS;GAAO,IAAI;GAAO;EACjE;AAGH,KAAI,WAAW,SAGb,QAAO;EACL,MAAM;GAAE,IAAI;GAAS,IAAI;GAAQ,IAAI;GAAS,IAAI;GAAQ;EAC1D,OAAO;GAAE,IAAI;GAAS,IAAI;GAAQ,IAAI;GAAS,IAAI;GAAQ;EAC3D,OAAO;GAAE,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ;EACzD,MAAM;GAAE,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ;EACxD,KAAK;GAAE,IAAI;GAAS,IAAI;GAAO,IAAI;GAAS,IAAI;GAAO;EACvD,QAAQ;GAAE,IAAI;GAAQ,IAAI;GAAO,IAAI,SAAS;GAAO,IAAI;GAAO;EACjE;AAIH,QAAO;EACL,OAAO;GAAE,IAAI;GAAS,IAAI;GAAQ,IAAI;GAAS,IAAI;GAAQ;EAC3D,OAAO;GAAE,IAAI;GAAS,IAAI;GAAQ,IAAI;GAAS,IAAI;GAAQ;EAC3D,MAAM;GAAE,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ;EACxD,MAAM;GAAE,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ,IAAI;GAAQ;EACxD,KAAK;GAAE,IAAI;GAAS,IAAI;GAAO,IAAI;GAAS,IAAI;GAAO;EACvD,QAAQ;GAAE,IAAI;GAAQ,IAAI;GAAO,IAAI,SAAS;GAAO,IAAI;GAAO;EACjE"}
@@ -0,0 +1,2 @@
1
+ import { PanoramaPlugin } from "./plugins/panorama/plugin.mjs";
2
+ export { PanoramaPlugin };
@@ -0,0 +1,3 @@
1
+ import { PanoramaPlugin } from "./plugins/panorama/plugin.mjs";
2
+
3
+ export { PanoramaPlugin };
@@ -0,0 +1,94 @@
1
+ import { BlendMode, BufferUsage, CullMode, DepthCompare, TextureFilter, TextureWrap, VertexFormat } from "../../core/renderer/types.mjs";
2
+ import { loadTexture } from "../../texture/TextureLoader.mjs";
3
+ import { createSkyboxGeometry } from "./SkyboxGeometry.mjs";
4
+ import { PANORAMA_FRAGMENT_SHADER, PANORAMA_VERTEX_SHADER } from "./shaders/webgl.mjs";
5
+ import { PANORAMA_WGSL_SHADER } from "./shaders/webgpu.mjs";
6
+
7
+ //#region src/plugins/panorama/PanoramaRenderer.ts
8
+ /**
9
+ * Get the appropriate shaders based on the renderer backend
10
+ */
11
+ function getShaders(renderer) {
12
+ if (renderer.backend === "webgpu") return {
13
+ vertexShader: PANORAMA_WGSL_SHADER,
14
+ fragmentShader: PANORAMA_WGSL_SHADER
15
+ };
16
+ return {
17
+ vertexShader: PANORAMA_VERTEX_SHADER,
18
+ fragmentShader: PANORAMA_FRAGMENT_SHADER
19
+ };
20
+ }
21
+ /**
22
+ * Create a panorama background renderer
23
+ */
24
+ function createPanoramaRenderer(renderer) {
25
+ const skybox = createSkyboxGeometry(2);
26
+ const vertexBuffer = renderer.createBuffer(BufferUsage.Vertex, skybox.vertices);
27
+ const indexBuffer = renderer.createBuffer(BufferUsage.Index, skybox.indices);
28
+ const vertexLayout = {
29
+ stride: 12,
30
+ attributes: [{
31
+ name: "a_position",
32
+ location: 0,
33
+ format: VertexFormat.Float32x3,
34
+ offset: 0
35
+ }]
36
+ };
37
+ const shaders = getShaders(renderer);
38
+ const pipeline = renderer.createPipeline({
39
+ vertexShader: shaders.vertexShader,
40
+ fragmentShader: shaders.fragmentShader,
41
+ vertexLayout,
42
+ cullMode: CullMode.Front,
43
+ depthWrite: false,
44
+ depthCompare: DepthCompare.LessEqual,
45
+ blendMode: BlendMode.None
46
+ });
47
+ let panoramaTexture = null;
48
+ const indexCount = skybox.indexCount;
49
+ return {
50
+ async setSource(source) {
51
+ if (panoramaTexture) {
52
+ panoramaTexture.dispose();
53
+ panoramaTexture = null;
54
+ }
55
+ const bitmap = await loadTexture(source);
56
+ panoramaTexture = await renderer.createTexture(bitmap, {
57
+ wrapU: TextureWrap.Repeat,
58
+ wrapV: TextureWrap.ClampToEdge,
59
+ minFilter: TextureFilter.Linear,
60
+ magFilter: TextureFilter.Linear,
61
+ generateMipmaps: true
62
+ });
63
+ },
64
+ render(camera) {
65
+ if (!panoramaTexture) return;
66
+ renderer.draw({
67
+ pipeline,
68
+ vertexBuffers: [vertexBuffer],
69
+ indexBuffer,
70
+ indexCount,
71
+ bindGroup: {
72
+ uniforms: {
73
+ u_viewMatrix: camera.viewMatrix,
74
+ u_projectionMatrix: camera.projectionMatrix
75
+ },
76
+ textures: { u_panorama: panoramaTexture }
77
+ }
78
+ });
79
+ },
80
+ dispose() {
81
+ vertexBuffer.dispose();
82
+ indexBuffer.dispose();
83
+ pipeline.dispose();
84
+ if (panoramaTexture) {
85
+ panoramaTexture.dispose();
86
+ panoramaTexture = null;
87
+ }
88
+ }
89
+ };
90
+ }
91
+
92
+ //#endregion
93
+ export { createPanoramaRenderer };
94
+ //# sourceMappingURL=PanoramaRenderer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PanoramaRenderer.mjs","names":[],"sources":["../../../src/plugins/panorama/PanoramaRenderer.ts"],"sourcesContent":["/**\n * Panorama Renderer\n *\n * Renders equirectangular panorama images as a background skybox.\n */\n\nimport type { Camera } from \"../../core/camera/Camera\";\nimport type { IRenderer, ITexture } from \"../../core/renderer/types\";\nimport {\n BufferUsage,\n CullMode,\n DepthCompare,\n BlendMode,\n VertexFormat,\n TextureWrap,\n TextureFilter,\n} from \"../../core/renderer/types\";\nimport type { TextureSource } from \"../../texture\";\nimport { loadTexture } from \"../../texture\";\nimport type { BackgroundRenderer } from \"../../core/plugins/types\";\nimport { createSkyboxGeometry } from \"./SkyboxGeometry\";\nimport { PANORAMA_VERTEX_SHADER, PANORAMA_FRAGMENT_SHADER } from \"./shaders/webgl\";\nimport { PANORAMA_WGSL_SHADER } from \"./shaders/webgpu\";\n\n/**\n * Get the appropriate shaders based on the renderer backend\n */\nfunction getShaders(renderer: IRenderer): { vertexShader: string; fragmentShader: string } {\n if (renderer.backend === \"webgpu\") {\n // WebGPU uses a combined WGSL shader\n return {\n vertexShader: PANORAMA_WGSL_SHADER,\n fragmentShader: PANORAMA_WGSL_SHADER,\n };\n }\n // WebGL uses separate vertex and fragment shaders\n return {\n vertexShader: PANORAMA_VERTEX_SHADER,\n fragmentShader: PANORAMA_FRAGMENT_SHADER,\n };\n}\n\n/**\n * Create a panorama background renderer\n */\nexport function createPanoramaRenderer(renderer: IRenderer): BackgroundRenderer {\n // Create skybox geometry\n const skybox = createSkyboxGeometry(2.0);\n\n // Create vertex buffer (position only, vec3)\n const vertexBuffer = renderer.createBuffer(BufferUsage.Vertex, skybox.vertices);\n const indexBuffer = renderer.createBuffer(BufferUsage.Index, skybox.indices);\n\n // Vertex layout for skybox (just position)\n const vertexLayout = {\n stride: 12, // 3 floats * 4 bytes\n attributes: [{ name: \"a_position\", location: 0, format: VertexFormat.Float32x3, offset: 0 }],\n };\n\n // Get shaders based on backend\n const shaders = getShaders(renderer);\n\n // Create pipeline for panorama rendering\n // - Cull front faces (we're inside the cube, render back faces)\n // - Depth test less-or-equal (skybox is at far plane)\n // - No depth write (don't affect depth buffer)\n const pipeline = renderer.createPipeline({\n vertexShader: shaders.vertexShader,\n fragmentShader: shaders.fragmentShader,\n vertexLayout,\n cullMode: CullMode.Front, // Render inside of cube\n depthWrite: false, // Don't write to depth buffer\n depthCompare: DepthCompare.LessEqual, // Always pass at far plane\n blendMode: BlendMode.None,\n });\n\n let panoramaTexture: ITexture | null = null;\n const indexCount = skybox.indexCount;\n\n return {\n async setSource(source: TextureSource): Promise<void> {\n // Dispose old texture if exists\n if (panoramaTexture) {\n panoramaTexture.dispose();\n panoramaTexture = null;\n }\n\n // Load new texture\n const bitmap = await loadTexture(source);\n panoramaTexture = await renderer.createTexture(bitmap, {\n wrapU: TextureWrap.Repeat, // Wrap horizontally\n wrapV: TextureWrap.ClampToEdge, // Clamp vertically\n minFilter: TextureFilter.Linear,\n magFilter: TextureFilter.Linear,\n generateMipmaps: true,\n });\n },\n\n render(camera: Camera): void {\n if (!panoramaTexture) return;\n\n renderer.draw({\n pipeline,\n vertexBuffers: [vertexBuffer],\n indexBuffer,\n indexCount,\n bindGroup: {\n uniforms: {\n u_viewMatrix: camera.viewMatrix,\n u_projectionMatrix: camera.projectionMatrix,\n },\n textures: {\n u_panorama: panoramaTexture,\n },\n },\n });\n },\n\n dispose(): void {\n vertexBuffer.dispose();\n indexBuffer.dispose();\n pipeline.dispose();\n if (panoramaTexture) {\n panoramaTexture.dispose();\n panoramaTexture = null;\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;AA2BA,SAAS,WAAW,UAAuE;AACzF,KAAI,SAAS,YAAY,SAEvB,QAAO;EACL,cAAc;EACd,gBAAgB;EACjB;AAGH,QAAO;EACL,cAAc;EACd,gBAAgB;EACjB;;;;;AAMH,SAAgB,uBAAuB,UAAyC;CAE9E,MAAM,SAAS,qBAAqB,EAAI;CAGxC,MAAM,eAAe,SAAS,aAAa,YAAY,QAAQ,OAAO,SAAS;CAC/E,MAAM,cAAc,SAAS,aAAa,YAAY,OAAO,OAAO,QAAQ;CAG5E,MAAM,eAAe;EACnB,QAAQ;EACR,YAAY,CAAC;GAAE,MAAM;GAAc,UAAU;GAAG,QAAQ,aAAa;GAAW,QAAQ;GAAG,CAAC;EAC7F;CAGD,MAAM,UAAU,WAAW,SAAS;CAMpC,MAAM,WAAW,SAAS,eAAe;EACvC,cAAc,QAAQ;EACtB,gBAAgB,QAAQ;EACxB;EACA,UAAU,SAAS;EACnB,YAAY;EACZ,cAAc,aAAa;EAC3B,WAAW,UAAU;EACtB,CAAC;CAEF,IAAI,kBAAmC;CACvC,MAAM,aAAa,OAAO;AAE1B,QAAO;EACL,MAAM,UAAU,QAAsC;AAEpD,OAAI,iBAAiB;AACnB,oBAAgB,SAAS;AACzB,sBAAkB;;GAIpB,MAAM,SAAS,MAAM,YAAY,OAAO;AACxC,qBAAkB,MAAM,SAAS,cAAc,QAAQ;IACrD,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,WAAW,cAAc;IACzB,WAAW,cAAc;IACzB,iBAAiB;IAClB,CAAC;;EAGJ,OAAO,QAAsB;AAC3B,OAAI,CAAC,gBAAiB;AAEtB,YAAS,KAAK;IACZ;IACA,eAAe,CAAC,aAAa;IAC7B;IACA;IACA,WAAW;KACT,UAAU;MACR,cAAc,OAAO;MACrB,oBAAoB,OAAO;MAC5B;KACD,UAAU,EACR,YAAY,iBACb;KACF;IACF,CAAC;;EAGJ,UAAgB;AACd,gBAAa,SAAS;AACtB,eAAY,SAAS;AACrB,YAAS,SAAS;AAClB,OAAI,iBAAiB;AACnB,oBAAgB,SAAS;AACzB,sBAAkB;;;EAGvB"}