hoi4-agent-tools 3.0.3 → 3.0.4

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@
4
4
 
5
5
  No unreleased changes.
6
6
 
7
+ ## 3.0.4 - 2026-09-01
8
+
9
+ - Reconstruct enlarged HOI4 bitmap-font antialias edges at the target pixel density and snap bitmap glyphs to the output grid so fractional and high-scale renders remain crisp without changing the declared font face or metrics.
10
+ - Normalize opaque coverage in compressed language atlases before applying localisation colours, preventing faint glyph masks from turning coloured text grey, translucent, or empty on local and VPS renders.
11
+ - Extend the installed-game font audit to shape every language-override descriptor at 4× in addition to its native and 2× sizes while retaining complete mixed-colour base-font renders.
12
+
7
13
  ## 3.0.3 - 2026-08-31
8
14
 
9
15
  - Authenticate the final read-only GitHub API provenance check with the workflow token so shared-runner anonymous rate limits cannot leave a valid public release red.
@@ -922,18 +922,67 @@ export class GuiAssetCatalog {
922
922
  }
923
923
  }
924
924
  }
925
- const encodeMask = (pixels) => {
926
- let pipeline = sharp(pixels, {
925
+ const normalizeCoverage = (pixels) => {
926
+ if (pixels === undefined)
927
+ return;
928
+ let maximum = 0;
929
+ for (let offset = 3; offset < pixels.length; offset += 4)
930
+ maximum = Math.max(maximum, pixels[offset] ?? 0);
931
+ if (maximum <= 0 || maximum >= 255)
932
+ return;
933
+ for (let offset = 3; offset < pixels.length; offset += 4)
934
+ pixels[offset] = Math.round(((pixels[offset] ?? 0) * 255) / maximum);
935
+ };
936
+ // Font coverage masks describe opaque glyph faces. Block compression in several large
937
+ // language atlases lowers the maximum stored sample, which otherwise makes localisation
938
+ // colours look grey or translucent even when the font definition is fully opaque.
939
+ normalizeCoverage(facePixels);
940
+ normalizeCoverage(borderPixels);
941
+ const encodeMask = async (pixels) => {
942
+ const source = sharp(pixels, {
927
943
  raw: { width: extracted.info.width, height: extracted.info.height, channels: 4 },
928
944
  limitInputPixels: RENDER_MAX_DECODED_PIXELS,
929
945
  });
930
946
  if (targetWidth !== extracted.info.width || targetHeight !== extracted.info.height) {
931
- pipeline = pipeline.resize(targetWidth, targetHeight, {
947
+ const resized = await source
948
+ .resize(targetWidth, targetHeight, {
932
949
  fit: 'fill',
933
- kernel: scale >= 1 ? sharp.kernel.nearest : sharp.kernel.lanczos3,
934
- });
950
+ kernel: scale > 1 ? sharp.kernel.lanczos3 : sharp.kernel.nearest,
951
+ })
952
+ .ensureAlpha()
953
+ .raw()
954
+ .toBuffer({ resolveWithObject: true });
955
+ if (scale > 1) {
956
+ // BMFont antialiasing is authored for the descriptor's native point size. A plain
957
+ // enlargement makes that one-pixel edge band several pixels wide, which is why a
958
+ // high-DPI preview looks blurry and why differently-antialiased faces appear to
959
+ // change size. Reconstruct the edge at the target pixel density, then retain a
960
+ // one-pixel coverage transition just as the native atlas does.
961
+ const edgeGain = Math.max(1, scale);
962
+ let maximumCoverage = 0;
963
+ for (let offset = 3; offset < resized.data.length; offset += 4)
964
+ maximumCoverage = Math.max(maximumCoverage, resized.data[offset] ?? 0);
965
+ // Several compressed CJK atlases intentionally use a coverage range below 128.
966
+ // Centre the reconstruction inside the glyph's real range so a faint but valid
967
+ // face cannot be sharpened into complete transparency.
968
+ const edgeCentre = Math.min(127.5, maximumCoverage / 2);
969
+ for (let offset = 3; offset < resized.data.length; offset += 4) {
970
+ const coverage = resized.data[offset] ?? 0;
971
+ resized.data[offset] = Math.round(Math.max(0, Math.min(255, (coverage - edgeCentre) * edgeGain + edgeCentre)));
972
+ }
973
+ }
974
+ return sharp(resized.data, {
975
+ raw: {
976
+ width: resized.info.width,
977
+ height: resized.info.height,
978
+ channels: 4,
979
+ },
980
+ limitInputPixels: RENDER_MAX_DECODED_PIXELS,
981
+ })
982
+ .png({ compressionLevel: 9, adaptiveFiltering: false, palette: false })
983
+ .toBuffer();
935
984
  }
936
- return pipeline
985
+ return source
937
986
  .png({ compressionLevel: 9, adaptiveFiltering: false, palette: false })
938
987
  .toBuffer();
939
988
  };
@@ -81,8 +81,7 @@ function actualGlyphMarkup(glyphLine, originX, baseline, horizontalScale, bitmap
81
81
  .filter((glyph) => glyph.kind === 'bitmap')
82
82
  .filter((glyph) => bitmapLayer === 'face' || glyph.borderDataUri !== undefined)
83
83
  .map((glyph) => {
84
- const nativePixelGrid = Math.abs(horizontalScale - 1) < 0.000_001 &&
85
- [glyph.x, glyph.y, glyph.width, glyph.height, glyphLine.baseline].every((value) => Math.abs(value - Math.round(value)) < 0.000_001);
84
+ const nativePixelGrid = Math.abs(horizontalScale - 1) < 0.000_001;
86
85
  const x = originX + glyph.x * horizontalScale;
87
86
  const y = baseline + glyph.y - glyphLine.baseline;
88
87
  return `<use href="#${bitmapDefinitionId(glyph.key, bitmapLayer)}" transform="translate(${finite(nativePixelGrid ? Math.round(x) : x)} ${finite(nativePixelGrid ? Math.round(y) : y)}) scale(${finite(horizontalScale)} 1)" image-rendering="optimizeSpeed" style="image-rendering:pixelated"/>`;
@@ -1,6 +1,6 @@
1
1
  import { LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';
2
2
  export const PACKAGE_NAME = 'hoi4-agent-tools';
3
- export const PACKAGE_VERSION = '3.0.3';
3
+ export const PACKAGE_VERSION = '3.0.4';
4
4
  export const MCP_PROTOCOL_VERSION = LATEST_PROTOCOL_VERSION;
5
5
  export const CONFIG_VERSION = 1;
6
6
  export const TRANSACTION_VERSION = 1;
package/docs/gui.md CHANGED
@@ -35,7 +35,7 @@ The renderer resolves sprites and fonts through the complete mod, dependency, an
35
35
 
36
36
  Bitmap text uses the language-appropriate HOI4 font definition and its real glyph atlas. Header, serif, compact, typewriter, black, inverted, and other declared faces keep their own glyph shapes, native metrics, face colour, border colour, language override, and font-specific `textcolors` palette. The renderer reads BMFont channel roles, separates face and outline coverage, and recognizes both vanilla black-on-white masks and conventional white-on-transparent custom masks. HOI4 localisation colour runs such as `§Y` and `§R` therefore colour the glyph face while retaining its sharp antialiasing and declared border instead of flattening the glyph into a blurred monochrome mask or switching to the tool font. The default language uses the base font rather than an unrelated language override, and the renderer recognizes installed-game atlases whose filename omits a page suffix declared by the matching `.fnt` file.
37
37
 
38
- `uiScale` is the in-game UI scale, not an image zoom. Use `1` for the normal 1920×1080 layout. Enlarged bitmap-font glyphs are pre-scaled from their real atlas with deterministic pixel sampling, and bitmap colours use alpha masks so local and VPS renders produce the same pixels.
38
+ `uiScale` is the in-game UI scale, not an image zoom. Use `1` for the normal 1920×1080 layout. Enlarged bitmap-font glyphs retain their real atlas contours while reconstructing the atlas's native one-pixel antialias edge at the target pixel density; this prevents soft edge pixels from widening with the scale. Bitmap placement is snapped to the output pixel grid, and bitmap colours use alpha masks, so native, fractional-scale, local, and VPS renders remain sharp and deterministic.
39
39
 
40
40
  Layout follows Clausewitz orientation and element-origin anchors, including `CENTER_LEFT`, `CENTER_RIGHT`, `CENTER_UP`, `CENTER_DOWN`, `origo`, `centerposition`, inherited container coordinate origins, local scale, and both `%` and `%%` relative dimensions. Text boxes use native font metrics together with `maxWidth`, `maxHeight`, alignment, wrapping, and `fixedsize` clipping. Cornered tile sprites use fixed nine-slice borders and optional center tiling; progress bars composite their filled and background textures; masked shields composite their background and mask textures.
41
41
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hoi4-agent-tools",
3
3
  "mcpName": "io.github.klimPaskov/hoi4-agent-tools",
4
- "version": "3.0.3",
4
+ "version": "3.0.4",
5
5
  "description": "Analyze HOI4 events, tech trees, AI weights, and MTTH; build focus trees, GUIs, and maps.",
6
6
  "type": "module",
7
7
  "license": "Apache-2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/configuration.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/configuration.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/continuous-focus-palette.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/continuous-focus-palette.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/custom-weighted-pool.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/custom-weighted-pool.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/event-feature-manifest.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/event-feature-manifest.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/focus-plan.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/focus-plan.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/focus-planning-sidecar.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/focus-planning-sidecar.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/gui-animation-source.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/gui-animation-source.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/gui-helper.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/gui-helper.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/gui-scenario.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/gui-scenario.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/map-operation.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/map-operation.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "oneOf": [
5
5
  {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/operation-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/operation-result.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/probability-analysis-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/probability-analysis-result.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/probability-compare-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/probability-compare-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/probability-evaluate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/probability-evaluate-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/probability-inspect-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/probability-inspect-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/probability-render-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/probability-render-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/probability-scenario-set.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/probability-scenario-set.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/probability-sequence-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/probability-sequence-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/probability-simulate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/probability-simulate-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.3/schemas/probability-sweep-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.4/schemas/probability-sweep-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.klimPaskov/hoi4-agent-tools",
4
4
  "title": "HOI4 Agent Tools",
5
5
  "description": "Analyze HOI4 events, tech trees, AI weights, and MTTH; build focus trees, GUIs, and maps.",
6
- "version": "3.0.3",
6
+ "version": "3.0.4",
7
7
  "repository": {
8
8
  "url": "https://github.com/klimPaskov/hoi4-agent-tools",
9
9
  "source": "github"
@@ -13,7 +13,7 @@
13
13
  {
14
14
  "registryType": "npm",
15
15
  "identifier": "hoi4-agent-tools",
16
- "version": "3.0.3",
16
+ "version": "3.0.4",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  }