@nodecraft/rendermite 1.0.0 → 1.0.2

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.
package/README.md CHANGED
@@ -52,6 +52,7 @@ Useful flags: `--size <px>` (default 64), `--format webp|avif`, `--gif` for lega
52
52
  icons/
53
53
  items/<namespace>/<item>.png # always written
54
54
  items/<namespace>/<item>.webp # lossless, animated where the item animates
55
+ rc-enchantment.<format> # each lossless glint format referenced by the CSS
55
56
  rc-<namespace>-64.css # spritesheet CSS (class per item, enchant glint, tint layers)
56
57
  rc-<namespace>.json # rendered item id list
57
58
  rc-<namespace>-failures.json # per-item failures with reasons, never silent
@@ -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
  }
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-CEaRhk4A.js";
5
+ import { t as run } from "./run-Cp_wk49z.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";
@@ -6,6 +6,28 @@ import sharp from "sharp";
6
6
  * separate optimization step is needed: lossless everywhere, strictly-smaller
7
7
  * candidates only.
8
8
  */
9
+ /** Losslessly transcode an existing PNG resource into the formats referenced by generated CSS. */
10
+ async function encodeRasterAsset(source, formats) {
11
+ const image = sharp(source);
12
+ const unique = [...new Set(formats)];
13
+ const encoded = await Promise.all(unique.map(async (format) => {
14
+ switch (format) {
15
+ case "png": return [format, await image.clone().png({
16
+ compressionLevel: 9,
17
+ effort: 10
18
+ }).toBuffer()];
19
+ case "webp": return [format, await image.clone().webp({
20
+ lossless: true,
21
+ effort: 6
22
+ }).toBuffer()];
23
+ case "avif": return [format, await image.clone().avif({
24
+ lossless: true,
25
+ effort: 6
26
+ }).toBuffer()];
27
+ }
28
+ }));
29
+ return new Map(encoded);
30
+ }
9
31
  /**
10
32
  * Encode a multi-frame icon: animated WebP (universal), optional GIF for
11
33
  * legacy browsers, PNG as the static first frame (matching upstream's
@@ -83,4 +105,4 @@ async function encodeIcon(texture, options = {}) {
83
105
  return result;
84
106
  }
85
107
  //#endregion
86
- export { encodeIcon as n, encodeAnimatedIcon as t };
108
+ export { encodeIcon as n, encodeRasterAsset as r, encodeAnimatedIcon as t };
@@ -19,6 +19,9 @@ interface EncodedAnimatedIcon extends EncodedIcon {
19
19
  interface AnimatedEncodeOptions extends EncodeOptions {
20
20
  gif?: boolean;
21
21
  }
22
+ type RasterAssetFormat = 'png' | 'webp' | 'avif';
23
+ /** Losslessly transcode an existing PNG resource into the formats referenced by generated CSS. */
24
+ declare function encodeRasterAsset(source: Buffer, formats: readonly RasterAssetFormat[]): Promise<Map<RasterAssetFormat, Buffer>>;
22
25
  /**
23
26
  * Encode a multi-frame icon: animated WebP (universal), optional GIF for
24
27
  * legacy browsers, PNG as the static first frame (matching upstream's
@@ -28,4 +31,4 @@ interface AnimatedEncodeOptions extends EncodeOptions {
28
31
  declare function encodeAnimatedIcon(frames: FloatTexture[], delaysMs: number[], options?: AnimatedEncodeOptions): Promise<EncodedAnimatedIcon>;
29
32
  declare function encodeIcon(texture: FloatTexture, options?: EncodeOptions): Promise<EncodedIcon>;
30
33
  //#endregion
31
- export { encodeAnimatedIcon as a, EncodedIcon as i, EncodeOptions as n, encodeIcon as o, EncodedAnimatedIcon as r, AnimatedEncodeOptions as t };
34
+ export { RasterAssetFormat as a, encodeRasterAsset as c, EncodedIcon as i, EncodeOptions as n, encodeAnimatedIcon as o, EncodedAnimatedIcon as r, encodeIcon as s, AnimatedEncodeOptions 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-IC9DBUKp.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);
package/dist/index.d.ts CHANGED
@@ -10,11 +10,11 @@ import { a as pointResize, i as boxDownscale, n as RenderOptions, o as renderMod
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
12
  import { a as resolveTint, i as parseTintValue, n as InvalidTinterDefinitionError, o as resolveTints, t as DYE_COLORS } from "./tints-Fr6WoPaU.js";
13
- import { a as encodeAnimatedIcon, i as EncodedIcon, n as EncodeOptions, o as encodeIcon, r as EncodedAnimatedIcon, t as AnimatedEncodeOptions } from "./encode-BDB_VIHN.js";
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";
16
16
  import { i as prepareModResources } from "./prepare-DnnGGv9k.js";
17
17
  import { i as itemClass, n as StylesheetOptions, r as generateStylesheet, t as ItemStyle } from "./stylesheet-i-t_7sZ7.js";
18
- import { i as run, n as RunOptions, r as RunResult, t as ItemFailure } from "./run-D2XL05Zl.js";
18
+ import { i as run, n as RunOptions, r as RunResult, t as ItemFailure } from "./run-BK7Q8WZ3.js";
19
19
  import { n as UnsafeJarError, r as isUnsafeEntryPath, t as JarResourceManager } from "./jar-6T3xdgaL.js";
20
20
  export { type AnimatedEncodeOptions, AnimatedTexture, type AtlasResolver, type AtlasSource, AtlasSourceError, DYE_COLORS, type DiscoveredItem, type EncodeOptions, type EncodedAnimatedIcon, type EncodedIcon, type FloatTexture, FolderResourceManager, InvalidItemDefinitionError, InvalidResourceLocatorError, InvalidTinterDefinitionError, type ItemFailure, type ItemProperties, ItemRenderError, type ItemRenderInstruction, ItemResolutionError, type ItemStyle, JarResourceManager, LayeredResourceManager, type LightSource, LightingProfile, type LightingProfileName, ModelLoader, ModelResolutionError, type RenderOptions, type RenderedFrames, type ResolvedModel, type ResolvedSprite, ResourceKind, type ResourceKindName, ResourceLocator, type ResourceManager, type RunOptions, type RunResult, type StylesheetOptions, type Texture, TextureLoader, type TextureMeta, TextureResolutionError, type TintDefinition, 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 };
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-BR58A4Ye.js";
9
9
  import { o as toByteTexture, s as toFloatTexture } from "./blend-CHP2-j9U.js";
10
- import { n as encodeIcon, t as encodeAnimatedIcon } from "./encode-BdTHbOp-.js";
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-IC9DBUKp.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-CEaRhk4A.js";
17
+ import { t as run } from "./run-Cp_wk49z.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.
@@ -281,7 +286,7 @@ var ModelLoader = class {
281
286
  else if (isBuiltinParent(json.parent)) {
282
287
  builtinParent = normalizeBuiltin(json.parent);
283
288
  current = null;
284
- } else current = ResourceLocator.parse(json.parent);
289
+ } else current = ResourceLocator.parse(MODEL_PARENT_ALIASES[json.parent] ?? json.parent);
285
290
  }
286
291
  const textures = {};
287
292
  const display = {};
@@ -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-BR58A4Ye.js";
2
2
  export { ModelLoader, ModelResolutionError, flattenLoaderModel, resolveTexture, salvageJson };
@@ -1,2 +1,2 @@
1
- import { a as encodeAnimatedIcon, i as EncodedIcon, n as EncodeOptions, o as encodeIcon, r as EncodedAnimatedIcon, t as AnimatedEncodeOptions } from "../encode-BDB_VIHN.js";
2
- export { AnimatedEncodeOptions, EncodeOptions, EncodedAnimatedIcon, EncodedIcon, encodeAnimatedIcon, encodeIcon };
1
+ import { a as RasterAssetFormat, c as encodeRasterAsset, i as EncodedIcon, n as EncodeOptions, o as encodeAnimatedIcon, r as EncodedAnimatedIcon, s as encodeIcon, t as AnimatedEncodeOptions } from "../encode-C5kdAm45.js";
2
+ export { AnimatedEncodeOptions, EncodeOptions, EncodedAnimatedIcon, EncodedIcon, RasterAssetFormat, encodeAnimatedIcon, encodeIcon, encodeRasterAsset };
@@ -1,2 +1,2 @@
1
- import { n as encodeIcon, t as encodeAnimatedIcon } from "../encode-BdTHbOp-.js";
2
- export { encodeAnimatedIcon, encodeIcon };
1
+ import { n as encodeIcon, r as encodeRasterAsset, t as encodeAnimatedIcon } from "../encode-3u49i-eD.js";
2
+ export { encodeAnimatedIcon, encodeIcon, encodeRasterAsset };
@@ -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-D9iiUkkS.js";
2
2
  export { renderDyedVariantFallback, renderEntityFallback, spawnEggTints };
@@ -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-IC9DBUKp.js";
2
2
  export { parseMtl, parseObj, renderObjModel };
@@ -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-IC9DBUKp.js";
2
2
  export { ItemRenderError, boxDownscale, pointResize, renderModel, renderModelFrames };
@@ -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,6 +1,6 @@
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-BR58A4Ye.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
5
  import { t as combineFaceBuffers } from "./compose-cph4bfdr.js";
6
6
  import { i as phpRound, n as createFaceBuffer, r as drawTexturedTriangle, t as RowCursor } from "./rasterizer-ABgsWTYN.js";
@@ -46,7 +46,7 @@ interface RunResult {
46
46
  * from genuine misses.
47
47
  */
48
48
  skippedTemplates: string[];
49
- /** Files actually written, the only trustworthy success signal. */
49
+ /** Image files actually written, the only trustworthy success signal. */
50
50
  writtenFiles: number;
51
51
  }
52
52
  declare function run(options: RunOptions): Promise<RunResult>;
@@ -4,17 +4,17 @@ import { t as loadAtlasResolver } from "./registry-C9E7jyzG.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-BR58A4Ye.js";
8
8
  import { s as toFloatTexture, t as blendPixel } from "./blend-CHP2-j9U.js";
9
- import { t as encodeAnimatedIcon } from "./encode-BdTHbOp-.js";
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";
13
+ import { a as renderModelFrames, i as renderModel, n as boxDownscale, r as pointResize } from "./renderer-IC9DBUKp.js";
14
+ import { n as renderEntityFallback, r as spawnEggTints, t as renderDyedVariantFallback } from "./entity-fallback-D9iiUkkS.js";
15
15
  import { i as renderGeo, t as findGeoForItem } from "./geo-B5VqGulc.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";
@@ -29,6 +29,8 @@ async function run(options) {
29
29
  const size = options.size ?? 64;
30
30
  const quality = options.quality ?? 2;
31
31
  const prefix = options.prefix ?? "rc-";
32
+ const format = options.format ?? "webp";
33
+ const fallback = options.fallback ?? true;
32
34
  const lightingProfile = options.lightingProfile ?? "modern";
33
35
  const dynamic = options.builtin ? builtinDynamicResources() : null;
34
36
  const resources = options.builtin && dynamic ? new LayeredResourceManager([
@@ -38,6 +40,9 @@ async function run(options) {
38
40
  ]) : options.resources;
39
41
  const models = new ModelLoader(resources);
40
42
  const textures = new TextureLoader(resources);
43
+ const glint = await resolveEnchantmentGlint(resources);
44
+ if (!glint) throw new Error("Missing enchantment glint texture (minecraft:misc/enchanted_glint_item or enchanted_item_glint)");
45
+ const encodedGlint = await encodeRasterAsset(glint, fallback ? ["png", format] : [format]);
41
46
  textures.setAtlasResolver(await loadAtlasResolver(resources, (locator) => textures.load(locator)));
42
47
  const ids = [];
43
48
  const seen = /* @__PURE__ */ new Set();
@@ -70,6 +75,11 @@ async function run(options) {
70
75
  const skippedTemplates = [];
71
76
  const styles = [];
72
77
  let writtenFiles = 0;
78
+ await mkdir(options.output, { recursive: true });
79
+ for (const [extension, buffer] of encodedGlint) {
80
+ await writeFile(path.join(options.output, `${prefix}enchantment.${extension}`), buffer);
81
+ writtenFiles++;
82
+ }
73
83
  let templateParents = null;
74
84
  const loadTemplateParents = async () => {
75
85
  const parents = /* @__PURE__ */ new Set();
@@ -222,7 +232,7 @@ async function run(options) {
222
232
  const encoded = await encodeAnimatedIcon(frames, delaysMs, {
223
233
  webp: true,
224
234
  gif: options.gif,
225
- avif: options.avif
235
+ avif: options.avif || format === "avif"
226
236
  });
227
237
  const [namespace, itemPath] = id.split(":", 2);
228
238
  const imageBase = path.join(options.output, "items", namespace, `${itemPath}`);
@@ -265,8 +275,8 @@ async function run(options) {
265
275
  }
266
276
  const stylesheet = generateStylesheet(styles, {
267
277
  prefix,
268
- format: options.format ?? "webp",
269
- fallback: options.fallback ?? true
278
+ format,
279
+ fallback
270
280
  });
271
281
  const finalStylesheet = options.minify === false ? stylesheet : minifyStylesheet(stylesheet, (message) => options.onProgress?.(0, 0, "stylesheet", message));
272
282
  await writeFile(path.join(options.output, `${prefix}${namespaces[0]}-${size}.css`), finalStylesheet);
@@ -287,6 +297,14 @@ async function itemExistsIn(resources, id) {
287
297
  if (await resources.hasResource("itemDefinition", locator)) return true;
288
298
  return resources.hasResource("model", new ResourceLocator(locator.namespace, `item/${locator.path}`));
289
299
  }
300
+ /** Resolve both names used on either side of Minecraft 1.19.3. */
301
+ async function resolveEnchantmentGlint(resources) {
302
+ for (const path of ["misc/enchanted_glint_item", "misc/enchanted_item_glint"]) {
303
+ const texture = await resources.getResource("texture", new ResourceLocator("minecraft", path));
304
+ if (texture) return texture;
305
+ }
306
+ return null;
307
+ }
290
308
  function blendOver(base, layer) {
291
309
  for (let offset = 0; offset < base.data.length; offset += 4) {
292
310
  const alpha = layer.data[offset + 3];
package/dist/run.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { l as evaluateItemModel } from "./definition-BwX6Xxv0.js";
2
- import { i as run, n as RunOptions, r as RunResult, t as ItemFailure } from "./run-D2XL05Zl.js";
2
+ import { i as run, n as RunOptions, r as RunResult, t as ItemFailure } from "./run-BK7Q8WZ3.js";
3
3
  export { ItemFailure, RunOptions, RunResult, evaluateItemModel, run };
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-CEaRhk4A.js";
2
+ import { t as run } from "./run-Cp_wk49z.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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodecraft/rendermite",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
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",