@nodecraft/rendermite 1.0.1 → 1.0.3

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 (45) hide show
  1. package/assets/builtin/minecraft/models/block/template_shelf_inventory.json +69 -0
  2. package/assets/builtin/renderchest/models/item/bed.json +68 -0
  3. package/assets/builtin/renderchest/models/item/chest.json +7 -2
  4. package/dist/atlas/registry.js +1 -1
  5. package/dist/cli.js +1 -1
  6. package/dist/compose-qjhyBvnS.js +41 -0
  7. package/dist/{entity-fallback-CodtI6v8.js → entity-fallback-CdCVEG6X.js} +36 -3
  8. package/dist/{face-DC6cNMdz.d.ts → face-CpVdnf-w.d.ts} +1 -1
  9. package/dist/{face-Wfia-_Yx.js → face-D-N1amV4.js} +2 -2
  10. package/dist/{geo-B5VqGulc.js → geo-u8rndjLA.js} +2 -2
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +4 -4
  13. package/dist/{loader-C-eqwp3M.js → loader-A-BZa8J4.js} +17 -2
  14. package/dist/{loader-lCkMRDH4.d.ts → loader-C-6QN3xv.d.ts} +2 -0
  15. package/dist/models/loader.d.ts +1 -1
  16. package/dist/models/loader.js +1 -1
  17. package/dist/{rasterizer-ABgsWTYN.js → rasterizer-BHWDrmGz.js} +40 -1
  18. package/dist/{rasterizer-CVOlRsuw.d.ts → rasterizer-Dh35qXbn.d.ts} +10 -1
  19. package/dist/registry-B9TcjVbs.js +80 -0
  20. package/dist/render/compose.d.ts +1 -1
  21. package/dist/render/compose.js +1 -1
  22. package/dist/render/entity-fallback.d.ts +3 -3
  23. package/dist/render/entity-fallback.js +1 -1
  24. package/dist/render/face.d.ts +1 -1
  25. package/dist/render/face.js +1 -1
  26. package/dist/render/geo.d.ts +1 -1
  27. package/dist/render/geo.js +1 -1
  28. package/dist/render/legacy-tints.d.ts +1 -1
  29. package/dist/render/obj.d.ts +2 -2
  30. package/dist/render/obj.js +1 -1
  31. package/dist/render/rasterizer.d.ts +2 -2
  32. package/dist/render/rasterizer.js +2 -2
  33. package/dist/render/renderer.d.ts +1 -1
  34. package/dist/render/renderer.js +1 -1
  35. package/dist/render/tints.d.ts +1 -1
  36. package/dist/render/tints.js +1 -1
  37. package/dist/{renderer-CmOz6WI9.js → renderer-BeOinVC8.js} +21 -6
  38. package/dist/{renderer-DQfv6axF.d.ts → renderer-nbMCw1Pl.d.ts} +2 -2
  39. package/dist/{run-Dr6BfyN9.js → run-B9T3PCg3.js} +6 -6
  40. package/dist/run.js +1 -1
  41. package/dist/{tints-FQlxTzUL.js → tints-BtbHegpI.js} +1 -1
  42. package/dist/{tints-Fr6WoPaU.d.ts → tints-txt-8xI5.d.ts} +1 -1
  43. package/package.json +1 -1
  44. package/dist/compose-cph4bfdr.js +0 -27
  45. package/dist/registry-C9E7jyzG.js +0 -28
@@ -0,0 +1,69 @@
1
+ {
2
+ "parent": "block/block",
3
+ "display": {
4
+ "gui": {
5
+ "rotation": [30, 225, 0],
6
+ "translation": [2.5, -1.5, 0],
7
+ "scale": [0.625, 0.625, 0.625]
8
+ },
9
+ "fixed": {
10
+ "translation": [0, 0, -4],
11
+ "scale": [0.5, 0.5, 0.5]
12
+ },
13
+ "on_shelf": {
14
+ "rotation": [0, 180, 0],
15
+ "translation": [0, 0, 4]
16
+ },
17
+ "firstperson_righthand": {
18
+ "rotation": [0, 135, 0],
19
+ "translation": [0, -2, 0],
20
+ "scale": [0.5, 0.5, 0.5]
21
+ },
22
+ "thirdperson_righthand": {
23
+ "rotation": [75, 135, 0],
24
+ "translation": [-3, 1, 0],
25
+ "scale": [0.4, 0.4, 0.4]
26
+ }
27
+ },
28
+ "textures": {
29
+ "particle": "#particle"
30
+ },
31
+ "elements": [
32
+ {
33
+ "from": [0, 0, 13],
34
+ "to": [16, 16, 16],
35
+ "faces": {
36
+ "north": {"uv": [0, 2, 8, 6], "texture": "#all"},
37
+ "east": {"uv": [8, 0, 9.5, 8], "texture": "#all", "cullface": "east"},
38
+ "south": {"uv": [8, 0, 16, 8], "texture": "#all", "cullface": "south"},
39
+ "west": {"uv": [14.5, 0, 16, 8], "texture": "#all", "cullface": "west"},
40
+ "up": {"uv": [16, 5, 8, 3.5], "texture": "#all"},
41
+ "down": {"uv": [16, 6, 8, 4.5], "texture": "#all", "cullface": "down"}
42
+ }
43
+ },
44
+ {
45
+ "from": [0, 0, 11],
46
+ "to": [16, 4, 13],
47
+ "faces": {
48
+ "north": {"uv": [0, 6, 8, 8], "texture": "#all"},
49
+ "east": {"uv": [1.5, 6, 2.5, 8], "texture": "#all", "cullface": "east"},
50
+ "south": {"uv": [0, 0, 8, 1], "texture": "#all", "cullface": "south"},
51
+ "west": {"uv": [5.5, 6, 6.5, 8], "texture": "#all", "cullface": "west"},
52
+ "up": {"uv": [8, 3.5, 16, 4.5], "texture": "#all"},
53
+ "down": {"uv": [16, 4.5, 8, 3.5], "texture": "#all", "cullface": "down"}
54
+ }
55
+ },
56
+ {
57
+ "from": [0, 12, 11],
58
+ "to": [16, 16, 13],
59
+ "faces": {
60
+ "north": {"uv": [0, 0, 8, 2], "texture": "#all"},
61
+ "east": {"uv": [1.5, 0, 2.5, 2], "texture": "#all", "cullface": "east"},
62
+ "south": {"uv": [0, 0, 8, 1], "texture": "#all", "cullface": "south"},
63
+ "west": {"uv": [5.5, 0, 6.5, 2], "texture": "#all", "cullface": "west"},
64
+ "up": {"uv": [16, 6, 8, 5], "texture": "#all", "cullface": "up"},
65
+ "down": {"uv": [8, 5, 16, 6], "texture": "#all"}
66
+ }
67
+ }
68
+ ]
69
+ }
@@ -0,0 +1,68 @@
1
+ {
2
+ "texture_size": [64, 64],
3
+ "gui_light": "side",
4
+ "elements": [
5
+ {
6
+ "from": [0, 3, -8],
7
+ "to": [16, 9, 8],
8
+ "faces": {
9
+ "north": {"uv": [1.5, 1.5, 5.5, 0], "texture": "#texture"},
10
+ "east": {"uv": [5.5, 1.5, 7, 5.5], "rotation": 90, "texture": "#texture"},
11
+ "west": {"uv": [0, 1.5, 1.5, 5.5], "rotation": 270, "texture": "#texture"},
12
+ "up": {"uv": [1.5, 1.5, 5.5, 5.5], "texture": "#texture"},
13
+ "down": {"uv": [7, 1.5, 11, 5.5], "texture": "#texture"}
14
+ }
15
+ },
16
+ {
17
+ "from": [0, 3, 8],
18
+ "to": [16, 9, 24],
19
+ "faces": {
20
+ "east": {"uv": [5.5, 7, 7, 11], "rotation": 90, "texture": "#texture"},
21
+ "south": {"uv": [5.5, 7, 9.5, 5.5], "texture": "#texture"},
22
+ "west": {"uv": [0, 7, 1.5, 11], "rotation": 270, "texture": "#texture"},
23
+ "up": {"uv": [1.5, 7, 5.5, 11], "texture": "#texture"},
24
+ "down": {"uv": [7, 7, 11, 11], "texture": "#texture"}
25
+ }
26
+ },
27
+ {
28
+ "from": [0, 0, 21],
29
+ "to": [3, 3, 24],
30
+ "faces": {
31
+ "north": {"uv": [14.75, 2.25, 15.5, 3], "texture": "#texture"},
32
+ "east": {"uv": [14, 2.25, 14.75, 3], "texture": "#texture"},
33
+ "south": {"uv": [13.25, 2.25, 14, 3], "texture": "#texture"},
34
+ "west": {"uv": [12.5, 2.25, 13.25, 3], "texture": "#texture"},
35
+ "down": {"uv": [14, 1.5, 14.75, 2.25], "texture": "#texture"}
36
+ }
37
+ },
38
+ {
39
+ "from": [13, 0, 21],
40
+ "to": [16, 3, 24],
41
+ "faces": {
42
+ "north": {"uv": [14, 3.75, 14.75, 4.5], "texture": "#texture"},
43
+ "east": {"uv": [13.25, 3.75, 14, 4.5], "texture": "#texture"},
44
+ "south": {"uv": [12.5, 3.75, 13.25, 4.5], "texture": "#texture"},
45
+ "west": {"uv": [14.75, 3.75, 15.5, 4.5], "texture": "#texture"},
46
+ "down": {"uv": [14, 3, 14.75, 3.75], "texture": "#texture"}
47
+ }
48
+ },
49
+ {
50
+ "from": [13, 0, -8],
51
+ "to": [16, 3, -5],
52
+ "faces": {
53
+ "north": {"uv": [13.25, 5.25, 14, 6], "texture": "#texture"},
54
+ "east": {"uv": [12.5, 5.25, 13.25, 6], "texture": "#texture"},
55
+ "south": {"uv": [14.75, 5.25, 15.5, 6], "texture": "#texture"},
56
+ "west": {"uv": [14, 5.25, 14.75, 6], "texture": "#texture"},
57
+ "down": {"uv": [14, 4.5, 14.75, 5.25], "texture": "#texture"}
58
+ }
59
+ }
60
+ ],
61
+ "display": {
62
+ "gui": {
63
+ "rotation": [30, -20, 0],
64
+ "translation": [0, 1.75, 0],
65
+ "scale": [0.6, 0.59, 0.59]
66
+ }
67
+ }
68
+ }
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "credit": "Made with Blockbench",
3
- "parent": "minecraft:item/template_chest",
4
3
  "texture_size": [64, 64],
5
4
  "gui_light": "side",
6
5
  "elements": [
@@ -43,5 +42,11 @@
43
42
  "down": {"uv": [0.75, 0, 1.25, 0.25], "texture": "#texture"}
44
43
  }
45
44
  }
46
- ]
45
+ ],
46
+ "display": {
47
+ "gui": {
48
+ "rotation": [30, 45, 0],
49
+ "scale": [0.625, 0.625, 0.625]
50
+ }
51
+ }
47
52
  }
@@ -1,2 +1,2 @@
1
- import { t as loadAtlasResolver } from "../registry-C9E7jyzG.js";
1
+ import { t as loadAtlasResolver } from "../registry-B9TcjVbs.js";
2
2
  export { loadAtlasResolver };
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { n as builtinPackPath, t as bedCompatPath } from "./builtin-C8GZEN40.js";
3
3
  import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-dfI7b9N4.js";
4
4
  import { t as JarResourceManager } from "./jar-Bt3i0ls4.js";
5
- import { t as run } from "./run-Dr6BfyN9.js";
5
+ import { t as run } from "./run-B9T3PCg3.js";
6
6
  import { t as downloadClientJar } from "./download-D9aARBFp.js";
7
7
  import { a as prepareVersionResources, i as eraForVersion, n as GEOMETRY_DONOR_VERSIONS } from "./prepare-DROxBZp1.js";
8
8
  import path from "node:path";
@@ -0,0 +1,41 @@
1
+ import { t as blendPixel } from "./blend-CHP2-j9U.js";
2
+ //#region src/render/compose.ts
3
+ /**
4
+ * Per-pixel painter's compositing, mirroring upstream Model::combineFaceImages:
5
+ * at each pixel, faces sorted ascending by that pixel's depth value (0 where the
6
+ * rasterizer never wrote depth — the overdraw band relies on sorting beneath),
7
+ * then source-over blended in that order when alpha > 0.
8
+ */
9
+ function combineFaceBuffers(width, height, faces) {
10
+ const out = new Float64Array(width * height * 4);
11
+ const order = [...faces];
12
+ for (let pixel = 0; pixel < width * height; pixel++) {
13
+ const x = pixel % width;
14
+ const y = Math.floor(pixel / width);
15
+ const localPixel = (face) => {
16
+ const localX = x - face.x;
17
+ const localY = y - face.y;
18
+ return localX >= 0 && localX < face.width && localY >= 0 && localY < face.height ? localY * face.width + localX : null;
19
+ };
20
+ order.sort((a, b) => {
21
+ const aPixel = localPixel(a);
22
+ const bPixel = localPixel(b);
23
+ return (aPixel === null ? 0 : a.depths[aPixel]) - (bPixel === null ? 0 : b.depths[bPixel]);
24
+ });
25
+ const offset = pixel * 4;
26
+ for (const face of order) {
27
+ const facePixel = localPixel(face);
28
+ if (facePixel === null) continue;
29
+ const faceOffset = facePixel * 4;
30
+ const alpha = face.colors[faceOffset + 3];
31
+ if (alpha > 0) blendPixel(out, offset, face.colors[faceOffset], face.colors[faceOffset + 1], face.colors[faceOffset + 2], alpha);
32
+ }
33
+ }
34
+ return {
35
+ width,
36
+ height,
37
+ data: out
38
+ };
39
+ }
40
+ //#endregion
41
+ export { combineFaceBuffers as t };
@@ -1,5 +1,5 @@
1
1
  import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
2
- import { i as renderModel } from "./renderer-CmOz6WI9.js";
2
+ import { i as renderModel } from "./renderer-BeOinVC8.js";
3
3
  //#region src/render/entity-fallback.ts
4
4
  /**
5
5
  * Heuristic rendering for mod items that parent `builtin/entity` — chests,
@@ -14,6 +14,8 @@ import { i as renderModel } from "./renderer-CmOz6WI9.js";
14
14
  const FILLER_TOKENS = /* @__PURE__ */ new Set([
15
15
  "chest",
16
16
  "chests",
17
+ "crate",
18
+ "crates",
17
19
  "trapped",
18
20
  "big",
19
21
  "small",
@@ -46,12 +48,13 @@ async function findChestTexture(resources, namespace, itemName) {
46
48
  let bestScore = 0;
47
49
  let bestNoise = Infinity;
48
50
  for (const locator of await resources.listResources("texture", namespace)) {
49
- if (!locator.path.includes("chest")) continue;
51
+ if (!locator.path.includes("chest") && !locator.path.includes("crate")) continue;
50
52
  const candidate = tokens(locator.path);
51
53
  if (candidate.some((token) => SKIP_TOKENS.has(token))) continue;
52
54
  if (wantTrapped !== (candidate.includes("trapped") || candidate.includes("trap"))) continue;
53
55
  let score = 0;
54
56
  for (const token of wanted) if (candidate.includes(token)) score++;
57
+ if (locator.path.endsWith(`/${itemName}`) || locator.path.endsWith(`/${itemName}_0`)) score++;
55
58
  if (wanted.length > 0 && score === 0) continue;
56
59
  if (best === null || score > bestScore || score === bestScore && candidate.length < bestNoise) {
57
60
  best = locator;
@@ -96,6 +99,27 @@ const DYE_COLORS = {
96
99
  black: 1908001
97
100
  };
98
101
  const DYE_PREFIX = new RegExp(`^(${Object.keys(DYE_COLORS).join("|")})_(.+)$`);
102
+ /** Find a full modded bed entity sheet, preferring every distinguishing item-name token. */
103
+ async function findBedTexture(resources, namespace, itemName) {
104
+ const wanted = tokens(itemName).filter((token) => token !== "bed");
105
+ const hasDye = wanted.some((token) => Object.hasOwn(DYE_COLORS, token));
106
+ let best = null;
107
+ let bestScore = 0;
108
+ let bestNoise = Infinity;
109
+ for (const locator of await resources.listResources("texture", namespace)) {
110
+ if (!locator.path.startsWith("entity/") || !locator.path.includes("bed")) continue;
111
+ const candidate = tokens(locator.path);
112
+ let score = hasDye ? 0 : candidate.includes("undyed") ? 1 : 0;
113
+ for (const token of wanted) if (candidate.includes(token)) score++;
114
+ if (score === 0) continue;
115
+ if (best === null || score > bestScore || score === bestScore && candidate.length < bestNoise) {
116
+ best = locator;
117
+ bestScore = score;
118
+ bestNoise = candidate.length;
119
+ }
120
+ }
121
+ return best;
122
+ }
99
123
  /**
100
124
  * Dyed variants of vanilla items whose models mods generate at runtime (quark's
101
125
  * `black_frame_empty` parents a block model that exists nowhere on disk): render
@@ -229,7 +253,7 @@ async function renderEntityFallback(id, models, textures, resources, options) {
229
253
  }
230
254
  return null;
231
255
  }
232
- if (name.includes("chest") && !name.includes("chestplate")) {
256
+ if (name.includes("chest") && !name.includes("chestplate") || name.endsWith("_crate")) {
233
257
  const variant = name.includes("ender") ? "ender" : name.includes("trapped") ? "trapped" : "normal";
234
258
  const candidates = [[`renderchest:item/chest/${variant === "normal" ? "chest" : `${variant}_chest`}`, null], ["renderchest:item/chest", `minecraft:entity/chest/${variant}`]];
235
259
  const modTexture = await findChestTexture(resources, locator.namespace, name);
@@ -244,6 +268,15 @@ async function renderEntityFallback(id, models, textures, resources, options) {
244
268
  }
245
269
  return null;
246
270
  }
271
+ if (name === "bed" || name.endsWith("_bed")) {
272
+ const modTexture = await findBedTexture(resources, locator.namespace, name);
273
+ if (modTexture) try {
274
+ const model = await models.load("renderchest:item/bed");
275
+ return await renderModel(withTexture(model, "texture", modTexture), textures, options);
276
+ } catch {
277
+ return null;
278
+ }
279
+ }
247
280
  if (name.includes("shulker_box")) try {
248
281
  const model = await models.load("renderchest:item/shulker_box");
249
282
  return await renderModel(model, textures, options);
@@ -2,7 +2,7 @@ import { t as FloatTexture } from "./blend-Qvrn6YgK.js";
2
2
  import { t as Mat4 } from "./vector-DRKRi4--.js";
3
3
  import { n as FaceGeometry } from "./geometry-BSVmKx5b.js";
4
4
  import { r as LightSource } from "./lighting-3FGRC3Af.js";
5
- import { t as FaceBuffer } from "./rasterizer-CVOlRsuw.js";
5
+ import { t as FaceBuffer } from "./rasterizer-Dh35qXbn.js";
6
6
  //#region src/render/face.d.ts
7
7
  interface TintColor {
8
8
  r: number;
@@ -1,6 +1,6 @@
1
1
  import { c as normalize, g as transformVector, h as transformDirection, m as sub, r as dot, t as cross } from "./vector-CCxLae_T.js";
2
2
  import { a as tintTexture, n as cloneFloatTexture, r as darkenTexture } from "./blend-CHP2-j9U.js";
3
- import { i as phpRound, n as createFaceBuffer, r as drawTexturedTriangle, t as RowCursor } from "./rasterizer-ABgsWTYN.js";
3
+ import { a as phpRound, i as drawTexturedTriangle, n as compactFaceBuffer, r as createFaceBuffer, t as RowCursor } from "./rasterizer-BHWDrmGz.js";
4
4
  //#region src/render/face.ts
5
5
  /**
6
6
  * Face rendering: cull, transform, project, tint, darken, rasterize — a faithful
@@ -86,7 +86,7 @@ function renderFace(face, width, height, transformation) {
86
86
  const cursor = new RowCursor();
87
87
  drawTexturedTriangle(point(0), point(2), point(3), buffer, texture, cursor);
88
88
  drawTexturedTriangle(point(0), point(1), point(2), buffer, texture, cursor);
89
- return buffer;
89
+ return compactFaceBuffer(buffer);
90
90
  }
91
91
  //#endregion
92
92
  export { renderFace as n, faceMaxZ as t };
@@ -1,8 +1,8 @@
1
1
  import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
2
2
  import { n as displayMatrix } from "./vector-CCxLae_T.js";
3
3
  import { s as toFloatTexture } from "./blend-CHP2-j9U.js";
4
- import { t as combineFaceBuffers } from "./compose-cph4bfdr.js";
5
- import { n as renderFace, t as faceMaxZ } from "./face-Wfia-_Yx.js";
4
+ import { t as combineFaceBuffers } from "./compose-qjhyBvnS.js";
5
+ import { n as renderFace, t as faceMaxZ } from "./face-D-N1amV4.js";
6
6
  import { c as lightsForProfile } from "./lighting--5myudVu.js";
7
7
  //#region src/render/geo.ts
8
8
  /**
package/dist/index.d.ts CHANGED
@@ -3,13 +3,13 @@ import { a as ResourceManager, i as ResourceKindName, n as LayeredResourceManage
3
3
  import { a as TextureMeta, i as TextureLoader, o as TextureResolutionError, r as Texture, t as AnimatedTexture } from "./loader-TFFNV4Jl.js";
4
4
  import { d as parseAtlasSources, n as AtlasSource, r as AtlasSourceError, s as ResolvedSprite, t as AtlasResolver, u as createAtlasResolver } from "./sources-DH9dk3KF.js";
5
5
  import { s as builtinDynamicResources } from "./generators-CCB8h0mP.js";
6
- import { a as resolveTexture, n as ModelResolutionError, o as salvageJson, r as ResolvedModel, t as ModelLoader } from "./loader-lCkMRDH4.js";
6
+ import { a as resolveTexture, n as ModelResolutionError, o as salvageJson, r as ResolvedModel, t as ModelLoader } from "./loader-C-6QN3xv.js";
7
7
  import { c as toFloatTexture, s as toByteTexture, t as FloatTexture } from "./blend-Qvrn6YgK.js";
8
8
  import { a as LightingProfileName, i as LightingProfile, r as LightSource, u as lightsForProfile } from "./lighting-3FGRC3Af.js";
9
- import { a as pointResize, i as boxDownscale, n as RenderOptions, o as renderModel, r as RenderedFrames, s as renderModelFrames, t as ItemRenderError } from "./renderer-DQfv6axF.js";
9
+ import { a as pointResize, i as boxDownscale, n as RenderOptions, o as renderModel, r as RenderedFrames, s as renderModelFrames, t as ItemRenderError } from "./renderer-nbMCw1Pl.js";
10
10
  import { c as defaultProperties, i as ItemRenderInstruction, l as evaluateItemModel, n as InvalidItemDefinitionError, o as TintDefinition, r as ItemProperties, s as UNKNOWN_MODEL } from "./definition-BwX6Xxv0.js";
11
11
  import { i as resolveItem, n as ItemResolutionError, r as discoverItems, t as DiscoveredItem } from "./discovery-CmNYzKPr.js";
12
- import { a as resolveTint, i as parseTintValue, n as InvalidTinterDefinitionError, o as resolveTints, t as DYE_COLORS } from "./tints-Fr6WoPaU.js";
12
+ import { a as resolveTint, i as parseTintValue, n as InvalidTinterDefinitionError, o as resolveTints, t as DYE_COLORS } from "./tints-txt-8xI5.js";
13
13
  import { i as EncodedIcon, n as EncodeOptions, o as encodeAnimatedIcon, r as EncodedAnimatedIcon, s as encodeIcon, t as AnimatedEncodeOptions } from "./encode-C5kdAm45.js";
14
14
  import { t as minifyStylesheet } from "./minify-CIV6enbr.js";
15
15
  import { a as compareVersions, o as eraForVersion, s as prepareVersionResources } from "./prepare-wfWtaz_X.js";
package/dist/index.js CHANGED
@@ -5,16 +5,16 @@ import { o as createAtlasResolver, s as parseAtlasSources, t as AtlasSourceError
5
5
  import { a as builtinDynamicResources } from "./generators-CcVRG30y.js";
6
6
  import { a as defaultProperties, i as UNKNOWN_MODEL, n as InvalidItemDefinitionError, o as evaluateItemModel } from "./definition-3MBm8ar_.js";
7
7
  import { n as discoverItems, r as resolveItem, t as ItemResolutionError } from "./discovery-BzaOti7l.js";
8
- import { a as salvageJson, i as resolveTexture, n as ModelResolutionError, t as ModelLoader } from "./loader-C-eqwp3M.js";
8
+ import { a as salvageJson, i as resolveTexture, n as ModelResolutionError, t as ModelLoader } from "./loader-A-BZa8J4.js";
9
9
  import { o as toByteTexture, s as toFloatTexture } from "./blend-CHP2-j9U.js";
10
10
  import { n as encodeIcon, t as encodeAnimatedIcon } from "./encode-3u49i-eD.js";
11
11
  import { t as minifyStylesheet } from "./minify-bjMRmr5J.js";
12
12
  import { n as itemClass, t as generateStylesheet } from "./stylesheet-CovT3B2S.js";
13
13
  import { c as lightsForProfile, r as LightingProfile } from "./lighting--5myudVu.js";
14
- import { a as renderModelFrames, i as renderModel, n as boxDownscale, r as pointResize, t as ItemRenderError } from "./renderer-CmOz6WI9.js";
15
- import { a as resolveTints, i as resolveTint, n as InvalidTinterDefinitionError, r as parseTintValue, t as DYE_COLORS } from "./tints-FQlxTzUL.js";
14
+ import { a as renderModelFrames, i as renderModel, n as boxDownscale, r as pointResize, t as ItemRenderError } from "./renderer-BeOinVC8.js";
15
+ import { a as resolveTints, i as resolveTint, n as InvalidTinterDefinitionError, r as parseTintValue, t as DYE_COLORS } from "./tints-BtbHegpI.js";
16
16
  import { n as TextureLoader, r as TextureResolutionError, t as AnimatedTexture } from "./loader-CBzn3Koc.js";
17
- import { t as run } from "./run-Dr6BfyN9.js";
17
+ import { t as run } from "./run-B9T3PCg3.js";
18
18
  import { a as prepareVersionResources, i as eraForVersion, r as compareVersions } from "./prepare-DROxBZp1.js";
19
19
  import { n as prepareModResources } from "./prepare-Bvc5ve2m.js";
20
20
  export { AnimatedTexture, AtlasSourceError, DYE_COLORS, FolderResourceManager, InvalidItemDefinitionError, InvalidResourceLocatorError, InvalidTinterDefinitionError, ItemRenderError, ItemResolutionError, JarResourceManager, LayeredResourceManager, LightingProfile, ModelLoader, ModelResolutionError, ResourceKind, ResourceLocator, TextureLoader, TextureResolutionError, UNKNOWN_MODEL, UnsafeJarError, boxDownscale, builtinDynamicResources, compareVersions, createAtlasResolver, defaultProperties, discoverItems, encodeAnimatedIcon, encodeIcon, eraForVersion, evaluateItemModel, generateStylesheet, isUnsafeEntryPath, itemClass, lightsForProfile, minifyStylesheet, parseAtlasSources, parseTintValue, pointResize, prepareModResources, prepareVersionResources, renderModel, renderModelFrames, resolveItem, resolveTexture, resolveTint, resolveTints, run, salvageJson, toByteTexture, toFloatTexture };
@@ -3,6 +3,11 @@ import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
3
3
  var ModelResolutionError = class extends Error {};
4
4
  const MAX_PARENT_DEPTH = 64;
5
5
  const MAX_TEXTURE_REF_DEPTH = 16;
6
+ /** Forge's generated-item aliases are injected by the loader, not shipped as resources. */
7
+ const MODEL_PARENT_ALIASES = {
8
+ "forge:item/default": "minecraft:item/generated",
9
+ "forge:item/default-tool": "minecraft:item/handheld"
10
+ };
6
11
  /**
7
12
  * Per-mod synthesizers for loaders whose geometry lives entirely in Java but
8
13
  * whose icon shape is simple and stable enough to rebuild from the model json.
@@ -246,10 +251,20 @@ function salvageJson(text) {
246
251
  var ModelLoader = class {
247
252
  resources;
248
253
  cache = /* @__PURE__ */ new Map();
254
+ jsonCache = /* @__PURE__ */ new Map();
249
255
  constructor(resources) {
250
256
  this.resources = resources;
251
257
  }
252
- async readModelJson(locator) {
258
+ readModelJson(locator) {
259
+ const key = locator.toString();
260
+ let pending = this.jsonCache.get(key);
261
+ if (!pending) {
262
+ pending = this.loadModelJson(locator);
263
+ this.jsonCache.set(key, pending);
264
+ }
265
+ return pending;
266
+ }
267
+ async loadModelJson(locator) {
253
268
  const raw = await this.resources.getResource("model", locator);
254
269
  if (raw === null) throw new ModelResolutionError(`Model not found: ${locator}`);
255
270
  let json;
@@ -281,7 +296,7 @@ var ModelLoader = class {
281
296
  else if (isBuiltinParent(json.parent)) {
282
297
  builtinParent = normalizeBuiltin(json.parent);
283
298
  current = null;
284
- } else current = ResourceLocator.parse(json.parent);
299
+ } else current = ResourceLocator.parse(MODEL_PARENT_ALIASES[json.parent] ?? json.parent);
285
300
  }
286
301
  const textures = {};
287
302
  const display = {};
@@ -53,8 +53,10 @@ declare function salvageJson(text: string): unknown | null;
53
53
  declare class ModelLoader {
54
54
  private readonly resources;
55
55
  private readonly cache;
56
+ private readonly jsonCache;
56
57
  constructor(resources: ResourceManager);
57
58
  private readModelJson;
59
+ private loadModelJson;
58
60
  private resolve;
59
61
  /** Load and flatten a model by locator string (e.g. `minecraft:item/stone`). */
60
62
  load(locator: string | ResourceLocator): Promise<ResolvedModel>;
@@ -1,2 +1,2 @@
1
- import { a as resolveTexture, i as flattenLoaderModel, n as ModelResolutionError, o as salvageJson, r as ResolvedModel, t as ModelLoader } from "../loader-lCkMRDH4.js";
1
+ import { a as resolveTexture, i as flattenLoaderModel, n as ModelResolutionError, o as salvageJson, r as ResolvedModel, t as ModelLoader } from "../loader-C-6QN3xv.js";
2
2
  export { ModelLoader, ModelResolutionError, ResolvedModel, flattenLoaderModel, resolveTexture, salvageJson };
@@ -1,2 +1,2 @@
1
- import { a as salvageJson, i as resolveTexture, n as ModelResolutionError, r as flattenLoaderModel, t as ModelLoader } from "../loader-C-eqwp3M.js";
1
+ import { a as salvageJson, i as resolveTexture, n as ModelResolutionError, r as flattenLoaderModel, t as ModelLoader } from "../loader-A-BZa8J4.js";
2
2
  export { ModelLoader, ModelResolutionError, flattenLoaderModel, resolveTexture, salvageJson };
@@ -1,6 +1,8 @@
1
1
  //#region src/render/rasterizer.ts
2
2
  function createFaceBuffer(width, height) {
3
3
  return {
4
+ x: 0,
5
+ y: 0,
4
6
  width,
5
7
  height,
6
8
  colors: new Float64Array(width * height * 4),
@@ -8,6 +10,43 @@ function createFaceBuffer(width, height) {
8
10
  };
9
11
  }
10
12
  /**
13
+ * Retain only the rectangle containing visible pixels. Complex block models can
14
+ * contain thousands of tiny faces; keeping a full icon-sized color/depth buffer
15
+ * for each one turns a 64px render into gigabytes of transient memory.
16
+ */
17
+ function compactFaceBuffer(buffer) {
18
+ let minX = buffer.width;
19
+ let minY = buffer.height;
20
+ let maxX = -1;
21
+ let maxY = -1;
22
+ for (let y = 0; y < buffer.height; y++) for (let x = 0; x < buffer.width; x++) {
23
+ if (buffer.colors[(y * buffer.width + x) * 4 + 3] <= 0) continue;
24
+ minX = Math.min(minX, x);
25
+ minY = Math.min(minY, y);
26
+ maxX = Math.max(maxX, x);
27
+ maxY = Math.max(maxY, y);
28
+ }
29
+ if (maxX < minX || maxY < minY) return null;
30
+ const width = maxX - minX + 1;
31
+ const height = maxY - minY + 1;
32
+ const colors = new Float64Array(width * height * 4);
33
+ const depths = new Float64Array(width * height);
34
+ for (let y = 0; y < height; y++) {
35
+ const sourcePixel = (minY + y) * buffer.width + minX;
36
+ const targetPixel = y * width;
37
+ colors.set(buffer.colors.subarray(sourcePixel * 4, (sourcePixel + width) * 4), targetPixel * 4);
38
+ depths.set(buffer.depths.subarray(sourcePixel, sourcePixel + width), targetPixel);
39
+ }
40
+ return {
41
+ x: buffer.x + minX,
42
+ y: buffer.y + minY,
43
+ width,
44
+ height,
45
+ colors,
46
+ depths
47
+ };
48
+ }
49
+ /**
11
50
  * Emulates ImagickPixelIterator's cursor, including the quirk the whole
12
51
  * corpus is rendered with: next() on an unconsumed iterator (fresh or just
13
52
  * rewound) fetches row 0 instead of advancing. Upstream's moveIterator never
@@ -136,4 +175,4 @@ function drawTexturedTriangle(p1in, p2in, p3in, buffer, texture, cursor = new Ro
136
175
  }
137
176
  }
138
177
  //#endregion
139
- export { phpRound as i, createFaceBuffer as n, drawTexturedTriangle as r, RowCursor as t };
178
+ export { phpRound as a, drawTexturedTriangle as i, compactFaceBuffer as n, createFaceBuffer as r, RowCursor as t };
@@ -2,6 +2,9 @@ import { t as FloatTexture } from "./blend-Qvrn6YgK.js";
2
2
  //#region src/render/rasterizer.d.ts
3
3
  /** Per-face private color + depth buffers, image sized. */
4
4
  interface FaceBuffer {
5
+ /** Position within the final image (full-size scratch buffers start at 0,0). */
6
+ x: number;
7
+ y: number;
5
8
  width: number;
6
9
  height: number;
7
10
  /** RGBA float, overwritten (not blended) by the rasterizer. */
@@ -10,6 +13,12 @@ interface FaceBuffer {
10
13
  depths: Float64Array;
11
14
  }
12
15
  declare function createFaceBuffer(width: number, height: number): FaceBuffer;
16
+ /**
17
+ * Retain only the rectangle containing visible pixels. Complex block models can
18
+ * contain thousands of tiny faces; keeping a full icon-sized color/depth buffer
19
+ * for each one turns a 64px render into gigabytes of transient memory.
20
+ */
21
+ declare function compactFaceBuffer(buffer: FaceBuffer): FaceBuffer | null;
13
22
  interface RasterPoint {
14
23
  x: number;
15
24
  y: number;
@@ -38,4 +47,4 @@ declare class RowCursor {
38
47
  declare function phpRound(value: number): number;
39
48
  declare function drawTexturedTriangle(p1in: RasterPoint, p2in: RasterPoint, p3in: RasterPoint, buffer: FaceBuffer, texture: FloatTexture, cursor?: RowCursor): void;
40
49
  //#endregion
41
- export { drawTexturedTriangle as a, createFaceBuffer as i, RasterPoint as n, phpRound as o, RowCursor as r, FaceBuffer as t };
50
+ export { createFaceBuffer as a, compactFaceBuffer as i, RasterPoint as n, drawTexturedTriangle as o, RowCursor as r, phpRound as s, FaceBuffer as t };
@@ -0,0 +1,80 @@
1
+ import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
2
+ import { o as createAtlasResolver, r as PalettedPermutationsSource, s as parseAtlasSources } from "./sources-Bxk-WOzH.js";
3
+ //#region src/atlas/registry.ts
4
+ /**
5
+ * Collects every `atlases/*.json` across namespaces into one resolver.
6
+ * Load order matches upstream: sources from later-loaded files win, so the
7
+ * resolver checks sources in reverse. Unknown source types are skipped with a
8
+ * warning rather than failing the run (mods ship experimental types).
9
+ */
10
+ /**
11
+ * Some mods generate flat item-trim permutations in code rather than declaring
12
+ * them in an atlas. Infer only the exact Minecraft convention when all three
13
+ * inputs exist: `<type>_trim.png`, `trim_palette.png`, and the requested color
14
+ * palette. Direct files and authored atlas sources still take precedence.
15
+ */
16
+ var InferredItemTrimSource = class {
17
+ cache = /* @__PURE__ */ new Map();
18
+ resources;
19
+ loadTexture;
20
+ constructor(resources, loadTexture) {
21
+ this.resources = resources;
22
+ this.loadTexture = loadTexture;
23
+ }
24
+ async firstTexture(candidates) {
25
+ for (const candidate of candidates) if (await this.resources.hasResource("texture", candidate)) return candidate;
26
+ return null;
27
+ }
28
+ create(locator) {
29
+ const match = /^(trims\/items\/.+_trim)_(.+)$/.exec(locator.path);
30
+ if (!match) return Promise.resolve(null);
31
+ const [, basePath, variant] = match;
32
+ return (async () => {
33
+ const base = new ResourceLocator(locator.namespace, basePath);
34
+ if (!await this.resources.hasResource("texture", base)) return null;
35
+ const key = await this.firstTexture([new ResourceLocator(locator.namespace, "trims/color_palettes/trim_palette"), ResourceLocator.parse("minecraft:trims/color_palettes/trim_palette")]);
36
+ const palette = await this.firstTexture([new ResourceLocator(locator.namespace, `trims/color_palettes/${variant}`), ResourceLocator.parse(`minecraft:trims/color_palettes/${variant}`)]);
37
+ if (!key || !palette) return null;
38
+ return new PalettedPermutationsSource({
39
+ textures: [base.toString()],
40
+ palette_key: key.toString(),
41
+ permutations: { [variant]: palette.toString() }
42
+ }, this.loadTexture);
43
+ })();
44
+ }
45
+ source(locator) {
46
+ const key = locator.toString();
47
+ let pending = this.cache.get(key);
48
+ if (!pending) {
49
+ pending = this.create(locator);
50
+ this.cache.set(key, pending);
51
+ }
52
+ return pending;
53
+ }
54
+ async has(locator) {
55
+ return await this.source(locator) !== null;
56
+ }
57
+ async resolve(locator) {
58
+ return (await this.source(locator))?.resolve(locator) ?? null;
59
+ }
60
+ };
61
+ async function loadAtlasResolver(resources, loadTexture, onWarning) {
62
+ const sources = [new InferredItemTrimSource(resources, loadTexture)];
63
+ for (const namespace of await resources.listNamespaces()) {
64
+ const atlasFiles = await resources.listResources("atlas", namespace);
65
+ atlasFiles.sort((a, b) => a.path.localeCompare(b.path));
66
+ for (const file of atlasFiles) {
67
+ const copies = await resources.getAllResources("atlas", file);
68
+ copies.reverse();
69
+ for (const raw of copies) try {
70
+ const json = JSON.parse(raw.toString("utf8"));
71
+ sources.push(...parseAtlasSources(namespace, json, loadTexture, (type) => onWarning?.(`Skipping unknown atlas source type ${type} in ${file}`), (locator) => resources.hasResource("texture", locator)));
72
+ } catch (err) {
73
+ onWarning?.(`Unparseable atlas ${file}: ${err.message}`);
74
+ }
75
+ }
76
+ }
77
+ return createAtlasResolver(sources);
78
+ }
79
+ //#endregion
80
+ export { loadAtlasResolver as t };
@@ -1,5 +1,5 @@
1
1
  import { t as FloatTexture } from "../blend-Qvrn6YgK.js";
2
- import { t as FaceBuffer } from "../rasterizer-CVOlRsuw.js";
2
+ import { t as FaceBuffer } from "../rasterizer-Dh35qXbn.js";
3
3
  //#region src/render/compose.d.ts
4
4
  declare function combineFaceBuffers(width: number, height: number, faces: FaceBuffer[]): FloatTexture;
5
5
  //#endregion
@@ -1,2 +1,2 @@
1
- import { t as combineFaceBuffers } from "../compose-cph4bfdr.js";
1
+ import { t as combineFaceBuffers } from "../compose-qjhyBvnS.js";
2
2
  export { combineFaceBuffers };
@@ -1,9 +1,9 @@
1
1
  import { a as ResourceManager } from "../manager-CoZaeQTu.js";
2
2
  import { i as TextureLoader } from "../loader-TFFNV4Jl.js";
3
- import { t as ModelLoader } from "../loader-lCkMRDH4.js";
3
+ import { t as ModelLoader } from "../loader-C-6QN3xv.js";
4
4
  import { t as FloatTexture } from "../blend-Qvrn6YgK.js";
5
- import { n as TintColor } from "../face-DC6cNMdz.js";
6
- import { n as RenderOptions } from "../renderer-DQfv6axF.js";
5
+ import { n as TintColor } from "../face-CpVdnf-w.js";
6
+ import { n as RenderOptions } from "../renderer-nbMCw1Pl.js";
7
7
  //#region src/render/entity-fallback.d.ts
8
8
  /**
9
9
  * Dyed variants of vanilla items whose models mods generate at runtime (quark's
@@ -1,2 +1,2 @@
1
- import { n as renderEntityFallback, r as spawnEggTints, t as renderDyedVariantFallback } from "../entity-fallback-CodtI6v8.js";
1
+ import { n as renderEntityFallback, r as spawnEggTints, t as renderDyedVariantFallback } from "../entity-fallback-CdCVEG6X.js";
2
2
  export { renderDyedVariantFallback, renderEntityFallback, spawnEggTints };
@@ -1,2 +1,2 @@
1
- import { i as renderFace, n as TintColor, r as faceMaxZ, t as RenderableFace } from "../face-DC6cNMdz.js";
1
+ import { i as renderFace, n as TintColor, r as faceMaxZ, t as RenderableFace } from "../face-CpVdnf-w.js";
2
2
  export { RenderableFace, TintColor, faceMaxZ, renderFace };
@@ -1,2 +1,2 @@
1
- import { n as renderFace, t as faceMaxZ } from "../face-Wfia-_Yx.js";
1
+ import { n as renderFace, t as faceMaxZ } from "../face-D-N1amV4.js";
2
2
  export { faceMaxZ, renderFace };
@@ -3,7 +3,7 @@ import { a as ResourceManager } from "../manager-CoZaeQTu.js";
3
3
  import { i as TextureLoader } from "../loader-TFFNV4Jl.js";
4
4
  import { t as FloatTexture } from "../blend-Qvrn6YgK.js";
5
5
  import { n as FaceGeometry } from "../geometry-BSVmKx5b.js";
6
- import { n as RenderOptions } from "../renderer-DQfv6axF.js";
6
+ import { n as RenderOptions } from "../renderer-nbMCw1Pl.js";
7
7
  //#region src/render/geo.d.ts
8
8
  interface GeoCube {
9
9
  origin?: number[];
@@ -1,2 +1,2 @@
1
- import { i as renderGeo, n as geoToFaces, r as parseGeo, t as findGeoForItem } from "../geo-B5VqGulc.js";
1
+ import { i as renderGeo, n as geoToFaces, r as parseGeo, t as findGeoForItem } from "../geo-u8rndjLA.js";
2
2
  export { findGeoForItem, geoToFaces, parseGeo, renderGeo };
@@ -1,5 +1,5 @@
1
1
  import { i as TextureLoader } from "../loader-TFFNV4Jl.js";
2
- import { n as TintColor } from "../face-DC6cNMdz.js";
2
+ import { n as TintColor } from "../face-CpVdnf-w.js";
3
3
  //#region src/render/legacy-tints.d.ts
4
4
  /**
5
5
  * Tints for a model rendered without an item definition (pre-1.21.4 eras and
@@ -1,9 +1,9 @@
1
1
  import { a as ResourceManager } from "../manager-CoZaeQTu.js";
2
2
  import { i as TextureLoader } from "../loader-TFFNV4Jl.js";
3
- import { r as ResolvedModel } from "../loader-lCkMRDH4.js";
3
+ import { r as ResolvedModel } from "../loader-C-6QN3xv.js";
4
4
  import { t as FloatTexture } from "../blend-Qvrn6YgK.js";
5
5
  import { n as Vec3 } from "../vector-DRKRi4--.js";
6
- import { n as RenderOptions } from "../renderer-DQfv6axF.js";
6
+ import { n as RenderOptions } from "../renderer-nbMCw1Pl.js";
7
7
  //#region src/render/obj.d.ts
8
8
  interface ObjTriangle {
9
9
  positions: [Vec3, Vec3, Vec3];
@@ -1,2 +1,2 @@
1
- import { c as renderObjModel, o as parseMtl, s as parseObj } from "../renderer-CmOz6WI9.js";
1
+ import { c as renderObjModel, o as parseMtl, s as parseObj } from "../renderer-BeOinVC8.js";
2
2
  export { parseMtl, parseObj, renderObjModel };
@@ -1,2 +1,2 @@
1
- import { a as drawTexturedTriangle, i as createFaceBuffer, n as RasterPoint, o as phpRound, r as RowCursor, t as FaceBuffer } from "../rasterizer-CVOlRsuw.js";
2
- export { FaceBuffer, RasterPoint, RowCursor, createFaceBuffer, drawTexturedTriangle, phpRound };
1
+ import { a as createFaceBuffer, i as compactFaceBuffer, n as RasterPoint, o as drawTexturedTriangle, r as RowCursor, s as phpRound, t as FaceBuffer } from "../rasterizer-Dh35qXbn.js";
2
+ export { FaceBuffer, RasterPoint, RowCursor, compactFaceBuffer, createFaceBuffer, drawTexturedTriangle, phpRound };
@@ -1,2 +1,2 @@
1
- import { i as phpRound, n as createFaceBuffer, r as drawTexturedTriangle, t as RowCursor } from "../rasterizer-ABgsWTYN.js";
2
- export { RowCursor, createFaceBuffer, drawTexturedTriangle, phpRound };
1
+ import { a as phpRound, i as drawTexturedTriangle, n as compactFaceBuffer, r as createFaceBuffer, t as RowCursor } from "../rasterizer-BHWDrmGz.js";
2
+ export { RowCursor, compactFaceBuffer, createFaceBuffer, drawTexturedTriangle, phpRound };
@@ -1,2 +1,2 @@
1
- import { a as pointResize, i as boxDownscale, n as RenderOptions, o as renderModel, r as RenderedFrames, s as renderModelFrames, t as ItemRenderError } from "../renderer-DQfv6axF.js";
1
+ import { a as pointResize, i as boxDownscale, n as RenderOptions, o as renderModel, r as RenderedFrames, s as renderModelFrames, t as ItemRenderError } from "../renderer-nbMCw1Pl.js";
2
2
  export { ItemRenderError, RenderOptions, RenderedFrames, boxDownscale, pointResize, renderModel, renderModelFrames };
@@ -1,2 +1,2 @@
1
- import { a as renderModelFrames, i as renderModel, n as boxDownscale, r as pointResize, t as ItemRenderError } from "../renderer-CmOz6WI9.js";
1
+ import { a as renderModelFrames, i as renderModel, n as boxDownscale, r as pointResize, t as ItemRenderError } from "../renderer-BeOinVC8.js";
2
2
  export { ItemRenderError, boxDownscale, pointResize, renderModel, renderModelFrames };
@@ -1,2 +1,2 @@
1
- import { a as resolveTint, i as parseTintValue, n as InvalidTinterDefinitionError, o as resolveTints, r as TintContext, t as DYE_COLORS } from "../tints-Fr6WoPaU.js";
1
+ import { a as resolveTint, i as parseTintValue, n as InvalidTinterDefinitionError, o as resolveTints, r as TintContext, t as DYE_COLORS } from "../tints-txt-8xI5.js";
2
2
  export { DYE_COLORS, InvalidTinterDefinitionError, TintContext, parseTintValue, resolveTint, resolveTints };
@@ -1,2 +1,2 @@
1
- import { a as resolveTints, i as resolveTint, n as InvalidTinterDefinitionError, r as parseTintValue, t as DYE_COLORS } from "../tints-FQlxTzUL.js";
1
+ import { a as resolveTints, i as resolveTint, n as InvalidTinterDefinitionError, r as parseTintValue, t as DYE_COLORS } from "../tints-BtbHegpI.js";
2
2
  export { DYE_COLORS, InvalidTinterDefinitionError, parseTintValue, resolveTint, resolveTints };
@@ -1,10 +1,10 @@
1
1
  import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
2
2
  import { c as normalize, g as transformVector, m as sub, n as displayMatrix, o as identity, r as dot, s as multiply, t as cross } from "./vector-CCxLae_T.js";
3
- import { i as resolveTexture } from "./loader-C-eqwp3M.js";
3
+ import { i as resolveTexture } from "./loader-A-BZa8J4.js";
4
4
  import { a as tintTexture, n as cloneFloatTexture, r as darkenTexture, s as toFloatTexture, t as blendPixel } from "./blend-CHP2-j9U.js";
5
- import { t as combineFaceBuffers } from "./compose-cph4bfdr.js";
6
- import { i as phpRound, n as createFaceBuffer, r as drawTexturedTriangle, t as RowCursor } from "./rasterizer-ABgsWTYN.js";
7
- import { n as renderFace, t as faceMaxZ } from "./face-Wfia-_Yx.js";
5
+ import { t as combineFaceBuffers } from "./compose-qjhyBvnS.js";
6
+ import { a as phpRound, i as drawTexturedTriangle, r as createFaceBuffer, t as RowCursor } from "./rasterizer-BHWDrmGz.js";
7
+ import { n as renderFace, t as faceMaxZ } from "./face-D-N1amV4.js";
8
8
  import { t as paintBucketFluid } from "./fluid-bucket-D-GpUQjg.js";
9
9
  import { r as buildElementFaces } from "./geometry-uIDha8S4.js";
10
10
  import { c as lightsForProfile } from "./lighting--5myudVu.js";
@@ -394,17 +394,32 @@ async function renderElementModel(model, textures, renderSize, options) {
394
394
  async function renderElementModelWith(model, supplier, renderSize, options) {
395
395
  const lights = lightsForProfile(options.lightingProfile);
396
396
  const light = model.elementsGuiLight === "side" ? lights.side : lights.front;
397
+ const loadedTextures = /* @__PURE__ */ new Map();
398
+ const floatTextures = /* @__PURE__ */ new Map();
399
+ const load = (reference) => {
400
+ let pending = loadedTextures.get(reference);
401
+ if (!pending) {
402
+ pending = supplier(reference);
403
+ loadedTextures.set(reference, pending);
404
+ }
405
+ return pending;
406
+ };
397
407
  const faces = [];
398
408
  let skippedFaces = 0;
399
409
  for (const element of model.elements) for (const geometry of buildElementFaces(element)) {
400
- const texture = await supplier(geometry.textureRef);
410
+ const texture = await load(geometry.textureRef);
401
411
  if (!texture) {
402
412
  skippedFaces++;
403
413
  continue;
404
414
  }
415
+ let float = floatTextures.get(texture);
416
+ if (!float) {
417
+ float = toFloatTexture(texture);
418
+ floatTextures.set(texture, float);
419
+ }
405
420
  faces.push({
406
421
  geometry,
407
- texture: toFloatTexture(texture),
422
+ texture: float,
408
423
  light,
409
424
  tint: geometry.tintIndex !== null ? options.tints?.[geometry.tintIndex] ?? null : null,
410
425
  maxZ: faceMaxZ(geometry)
@@ -1,10 +1,10 @@
1
1
  import { a as ResourceManager } from "./manager-CoZaeQTu.js";
2
2
  import { i as TextureLoader } from "./loader-TFFNV4Jl.js";
3
- import { r as ResolvedModel } from "./loader-lCkMRDH4.js";
3
+ import { r as ResolvedModel } from "./loader-C-6QN3xv.js";
4
4
  import { t as FloatTexture } from "./blend-Qvrn6YgK.js";
5
5
  import { t as Mat4 } from "./vector-DRKRi4--.js";
6
6
  import { a as LightingProfileName } from "./lighting-3FGRC3Af.js";
7
- import { n as TintColor } from "./face-DC6cNMdz.js";
7
+ import { n as TintColor } from "./face-CpVdnf-w.js";
8
8
  //#region src/render/renderer.d.ts
9
9
  interface RenderOptions {
10
10
  size: number;
@@ -1,20 +1,20 @@
1
1
  import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
2
2
  import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-dfI7b9N4.js";
3
- import { t as loadAtlasResolver } from "./registry-C9E7jyzG.js";
3
+ import { t as loadAtlasResolver } from "./registry-B9TcjVbs.js";
4
4
  import { a as builtinDynamicResources } from "./generators-CcVRG30y.js";
5
5
  import { a as defaultProperties } from "./definition-3MBm8ar_.js";
6
6
  import { n as discoverItems, r as resolveItem } from "./discovery-BzaOti7l.js";
7
- import { t as ModelLoader } from "./loader-C-eqwp3M.js";
7
+ import { t as ModelLoader } from "./loader-A-BZa8J4.js";
8
8
  import { s as toFloatTexture, t as blendPixel } from "./blend-CHP2-j9U.js";
9
9
  import { r as encodeRasterAsset, t as encodeAnimatedIcon } from "./encode-3u49i-eD.js";
10
10
  import { t as classifyItemStyle } from "./item-styles-DJ3LWZS2.js";
11
11
  import { t as minifyStylesheet } from "./minify-bjMRmr5J.js";
12
12
  import { t as generateStylesheet } from "./stylesheet-CovT3B2S.js";
13
- import { a as renderModelFrames, i as renderModel, n as boxDownscale, r as pointResize } from "./renderer-CmOz6WI9.js";
14
- import { n as renderEntityFallback, r as spawnEggTints, t as renderDyedVariantFallback } from "./entity-fallback-CodtI6v8.js";
15
- import { i as renderGeo, t as findGeoForItem } from "./geo-B5VqGulc.js";
13
+ import { a as renderModelFrames, i as renderModel, n as boxDownscale, r as pointResize } from "./renderer-BeOinVC8.js";
14
+ import { n as renderEntityFallback, r as spawnEggTints, t as renderDyedVariantFallback } from "./entity-fallback-CdCVEG6X.js";
15
+ import { i as renderGeo, t as findGeoForItem } from "./geo-u8rndjLA.js";
16
16
  import { t as legacyTintsForChain } from "./legacy-tints-B09J0Rxh.js";
17
- import { a as resolveTints } from "./tints-FQlxTzUL.js";
17
+ import { a as resolveTints } from "./tints-BtbHegpI.js";
18
18
  import { n as TextureLoader } from "./loader-CBzn3Koc.js";
19
19
  import path from "node:path";
20
20
  import { mkdir, writeFile } from "node:fs/promises";
package/dist/run.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { o as evaluateItemModel } from "./definition-3MBm8ar_.js";
2
- import { t as run } from "./run-Dr6BfyN9.js";
2
+ import { t as run } from "./run-B9T3PCg3.js";
3
3
  export { evaluateItemModel, run };
@@ -76,7 +76,7 @@ async function resolveTint(definition, context) {
76
76
  return hexColor(DYE_COLORS[index % DYE_COLORS.length]);
77
77
  }
78
78
  default:
79
- if (DEFAULT_READING_TYPES.has(type)) return parseTintValue(definition.default);
79
+ if (DEFAULT_READING_TYPES.has(type) || Object.hasOwn(definition, "default")) return parseTintValue(definition.default);
80
80
  throw new InvalidTinterDefinitionError(`Unknown tint type: ${definition.type}`);
81
81
  }
82
82
  }
@@ -1,5 +1,5 @@
1
1
  import { i as TextureLoader } from "./loader-TFFNV4Jl.js";
2
- import { n as TintColor } from "./face-DC6cNMdz.js";
2
+ import { n as TintColor } from "./face-CpVdnf-w.js";
3
3
  import { o as TintDefinition } from "./definition-BwX6Xxv0.js";
4
4
  //#region src/render/tints.d.ts
5
5
  declare class InvalidTinterDefinitionError extends Error {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodecraft/rendermite",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Minecraft item icon renderer: renders inventory-identical item icons from vanilla and modded assets across game versions, outputting optimized PNG/WebP/AVIF plus CSS and a JSON item library.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,27 +0,0 @@
1
- import { t as blendPixel } from "./blend-CHP2-j9U.js";
2
- //#region src/render/compose.ts
3
- /**
4
- * Per-pixel painter's compositing, mirroring upstream Model::combineFaceImages:
5
- * at each pixel, faces sorted ascending by that pixel's depth value (0 where the
6
- * rasterizer never wrote depth — the overdraw band relies on sorting beneath),
7
- * then source-over blended in that order when alpha > 0.
8
- */
9
- function combineFaceBuffers(width, height, faces) {
10
- const out = new Float64Array(width * height * 4);
11
- const order = [...faces];
12
- for (let pixel = 0; pixel < width * height; pixel++) {
13
- order.sort((a, b) => a.depths[pixel] - b.depths[pixel]);
14
- const offset = pixel * 4;
15
- for (const face of order) {
16
- const alpha = face.colors[offset + 3];
17
- if (alpha > 0) blendPixel(out, offset, face.colors[offset], face.colors[offset + 1], face.colors[offset + 2], alpha);
18
- }
19
- }
20
- return {
21
- width,
22
- height,
23
- data: out
24
- };
25
- }
26
- //#endregion
27
- export { combineFaceBuffers as t };
@@ -1,28 +0,0 @@
1
- import { o as createAtlasResolver, s as parseAtlasSources } from "./sources-Bxk-WOzH.js";
2
- //#region src/atlas/registry.ts
3
- /**
4
- * Collects every `atlases/*.json` across namespaces into one resolver.
5
- * Load order matches upstream: sources from later-loaded files win, so the
6
- * resolver checks sources in reverse. Unknown source types are skipped with a
7
- * warning rather than failing the run (mods ship experimental types).
8
- */
9
- async function loadAtlasResolver(resources, loadTexture, onWarning) {
10
- const sources = [];
11
- for (const namespace of await resources.listNamespaces()) {
12
- const atlasFiles = await resources.listResources("atlas", namespace);
13
- atlasFiles.sort((a, b) => a.path.localeCompare(b.path));
14
- for (const file of atlasFiles) {
15
- const copies = await resources.getAllResources("atlas", file);
16
- copies.reverse();
17
- for (const raw of copies) try {
18
- const json = JSON.parse(raw.toString("utf8"));
19
- sources.push(...parseAtlasSources(namespace, json, loadTexture, (type) => onWarning?.(`Skipping unknown atlas source type ${type} in ${file}`), (locator) => resources.hasResource("texture", locator)));
20
- } catch (err) {
21
- onWarning?.(`Unparseable atlas ${file}: ${err.message}`);
22
- }
23
- }
24
- }
25
- return createAtlasResolver(sources);
26
- }
27
- //#endregion
28
- export { loadAtlasResolver as t };