@rickyzhangca/fpsr 0.0.1
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 +10 -0
- package/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/abort-CrgARaZd.js +43 -0
- package/dist/abort-CrgARaZd.js.map +1 -0
- package/dist/assets-Dy4fqZBV.d.ts +85 -0
- package/dist/assets-Dy4fqZBV.d.ts.map +1 -0
- package/dist/canvas.d.ts +98 -0
- package/dist/canvas.d.ts.map +1 -0
- package/dist/canvas.js +3 -0
- package/dist/execute-CRZV5zw1.js +963 -0
- package/dist/execute-CRZV5zw1.js.map +1 -0
- package/dist/host-DdX4g1YM.d.ts +34 -0
- package/dist/host-DdX4g1YM.d.ts.map +1 -0
- package/dist/index.d.ts +463 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1776 -0
- package/dist/index.js.map +1 -0
- package/dist/node.d.ts +16 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +101 -0
- package/dist/node.js.map +1 -0
- package/dist/planner.d.ts +418 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +96 -0
- package/dist/planner.js.map +1 -0
- package/dist/profile-CTN1Q5SI.d.ts +365 -0
- package/dist/profile-CTN1Q5SI.d.ts.map +1 -0
- package/dist/profile-DR4i6HDp.js +610 -0
- package/dist/profile-DR4i6HDp.js.map +1 -0
- package/dist/render-db-BFQIspDB.d.ts +426 -0
- package/dist/render-db-BFQIspDB.d.ts.map +1 -0
- package/dist/render-db.d.ts +2 -0
- package/dist/render-db.js +1 -0
- package/dist/tiled-draw-list-Dc-5Ledi.js +3990 -0
- package/dist/tiled-draw-list-Dc-5Ledi.js.map +1 -0
- package/dist/types-CHgZBSra.d.ts +105 -0
- package/dist/types-CHgZBSra.d.ts.map +1 -0
- package/dist/upgrade-planner-CNjnMHPJ.d.ts +385 -0
- package/dist/upgrade-planner-CNjnMHPJ.d.ts.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiled-draw-list-Dc-5Ledi.js","names":["isPlainObject","typed","typed","spriteDest","OUTER_PAD","ICON_SIZE","tileCenter","occupiedRows","tileKey","spriteDest","spriteDest","spriteDest","spriteDest","spriteDest"],"sources":["../src/alt-mode-signals.ts","../src/alt-mode-request-pin.ts","../src/types/blueprint.ts","../src/wire-connectors.ts","../src/migrate.ts","../src/resolve/shared.ts","../src/resolve/belts.ts","../src/pole-orientation.ts","../src/resolve/pipes.ts","../src/resolve/context.ts","../src/resolve/walls.ts","../src/resolve/index.ts","../src/alt-mode.ts","../src/blueprint-icons.ts","../src/deconstruction-planner.ts","../src/upgrade-planner.ts","../src/icon-resolve.ts","../src/plan/bounds.ts","../src/plan/deconstruction-planner.ts","../src/plan/upgrade-planner.ts","../src/cargo-bay-connections.ts","../src/plan/belt-readers.ts","../src/plan/circuit-connectors.ts","../src/plan/pipe-covers.ts","../src/snap-grid.ts","../src/plan/snap-grid.ts","../src/plan/tiles.ts","../src/plan/unsupported.ts","../src/plan/wires.ts","../src/plan/index.ts","../src/tiled-draw-list.ts"],"sourcesContent":["import type { BlueprintEntity, BlueprintFilter, SignalId } from \"./types/blueprint.js\";\nimport type { EntityRenderDef, RenderDb } from \"./types/render-db.js\";\n\nexport type AltSignal = SignalId & { type: string };\n\nconst SIGNAL_PREFIX: Record<string, string> = {\n item: \"item\",\n fluid: \"fluid\",\n virtual: \"virtual-signal\",\n \"virtual-signal\": \"virtual-signal\",\n entity: \"entity\",\n recipe: \"recipe\",\n quality: \"quality\",\n tile: \"tile\",\n \"space-location\": \"space-location\",\n \"asteroid-chunk\": \"asteroid-chunk\",\n};\n\nexport function asSignal(value: unknown, defaultType = \"item\"): AltSignal | undefined {\n if (typeof value === \"string\") return { name: value, type: defaultType };\n if (!value || typeof value !== \"object\") return undefined;\n const obj = value as Record<string, unknown>;\n if (obj.id && typeof obj.id === \"object\") return asSignal(obj.id, defaultType);\n if (obj.value && typeof obj.value === \"object\") return asSignal(obj.value, defaultType);\n if (obj.signal && typeof obj.signal === \"object\") return asSignal(obj.signal, defaultType);\n if (typeof obj.name !== \"string\") return undefined;\n return {\n name: obj.name,\n type: typeof obj.type === \"string\" ? obj.type : defaultType,\n ...(typeof obj.quality === \"string\" ? { quality: obj.quality } : {}),\n };\n}\n\nexport function signalKey(signal: SignalId): string {\n return `${signal.type ?? \"item\"}/${signal.name}/${signal.quality ?? \"normal\"}`;\n}\n\nexport function collectSignals(\n value: unknown,\n defaultType = \"item\",\n out: AltSignal[] = [],\n): AltSignal[] {\n if (Array.isArray(value)) {\n for (const item of value) collectSignals(item, defaultType, out);\n return out;\n }\n if (!value || typeof value !== \"object\") return out;\n const obj = value as Record<string, unknown>;\n const direct = asSignal(obj, defaultType);\n if (direct) {\n out.push(direct);\n return out;\n }\n for (const [key, child] of Object.entries(obj)) {\n if (key === \"index\" || key === \"count\" || key === \"comparator\") continue;\n collectSignals(child, defaultType, out);\n }\n return out;\n}\n\nexport function filterSignals(\n filters: BlueprintFilter[] | undefined,\n defaultType = \"item\",\n): AltSignal[] {\n return collectSignals(filters ?? [], defaultType);\n}\n\nexport function uniqueSignals(signals: AltSignal[]): AltSignal[] {\n const seen = new Set<string>();\n return signals.filter((signal) => {\n const key = signalKey(signal);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** Ordered render-db icon keys for a Blueprint SignalID (UI lookup chain). */\nexport function signalIconKeys(signal: SignalId): string[] {\n const type = signal.type ?? \"item\";\n const prefix = SIGNAL_PREFIX[type] ?? type;\n const primary = `${prefix}/${signal.name}`;\n\n switch (type) {\n case \"item\":\n return [primary, `entity/${signal.name}`, `recipe/${signal.name}`];\n case \"entity\":\n return [primary, `item/${signal.name}`];\n case \"recipe\":\n return [primary, `item/${signal.name}`];\n case \"tile\":\n return [primary];\n default:\n return [primary];\n }\n}\n\n/** Resolve Blueprint SignalID namespaces and tolerate older/default item shapes. */\nexport function altSignalFrame(db: RenderDb, signal: SignalId): number | undefined {\n for (const key of signalIconKeys(signal)) {\n const frame = db.icons[key];\n if (frame !== undefined) return frame;\n }\n return undefined;\n}\n\nexport function isSplitterType(def: EntityRenderDef): boolean {\n return def.protoType === \"splitter\" || def.protoType === \"lane-splitter\";\n}\n\n/** Splitter filters render on the output-priority lane, not as centered primary icons. */\nexport function splitterLaneFilter(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n): AltSignal | undefined {\n if (!isSplitterType(def)) return undefined;\n if (!entity.output_priority || entity.output_priority === \"none\") return undefined;\n return asSignal(entity.filter) ?? filterSignals(entity.filters)[0];\n}\n\nexport function entitySignals(entity: BlueprintEntity, def: EntityRenderDef): AltSignal[] {\n const signals: AltSignal[] = [];\n if (entity.recipe) {\n signals.push({ name: entity.recipe, type: \"recipe\", quality: entity.recipe_quality });\n }\n\n // Splitter output filters are placed on the priority lane in splitterPriorityCommands.\n if (!splitterLaneFilter(entity, def)) {\n const directFilter = asSignal(\n entity.filter,\n def.protoType === \"mining-drill\" ? \"entity\" : \"item\",\n );\n if (directFilter) signals.push(directFilter);\n signals.push(...filterSignals(entity.filters));\n }\n // Turret target `priority-list` is not shown as Factorio entity-info icons.\n signals.push(...filterSignals(entity[\"chunk-filter\"], \"asteroid-chunk\"));\n if (entity.fluid_filter) signals.push({ name: entity.fluid_filter, type: \"fluid\" });\n\n for (const inventory of [\n entity.inventory,\n entity.trunk_inventory,\n entity.ammo_inventory,\n entity.burner_fuel_inventory,\n entity[\"result-inventory\"],\n ]) {\n signals.push(...filterSignals(inventory?.filters));\n }\n signals.push(...collectSignals(entity.request_filters));\n // Combinator / display-panel control_behavior drives built-in graphics (or\n // conditional messages); Factorio does not dump those as entity-info icons.\n // Display panels only expose a static single entity.icon in alt mode.\n if (entity.icon) signals.push({ ...entity.icon, type: entity.icon.type ?? \"item\" });\n\n return uniqueSignals(signals);\n}\n\nexport type ResolvedAltSignal = { signal: AltSignal; frame: number };\n\nexport function resolveAltSignals(db: RenderDb, signals: AltSignal[]): ResolvedAltSignal[] {\n return signals\n .map((signal) => ({\n signal,\n frame: altSignalFrame(db, signal) ?? db.icons[\"utility/missing-icon\"],\n }))\n .filter((entry): entry is ResolvedAltSignal => entry.frame !== undefined);\n}\n","import type { BlueprintEntity } from \"./types/blueprint.js\";\nimport { RENDER_LAYERS, type IconCmd } from \"./types/draw-list.js\";\nimport type { EntityRenderDef, RenderDb } from \"./types/render-db.js\";\nimport { type AltSignal, asSignal, entitySignals, resolveAltSignals } from \"./alt-mode-signals.js\";\n\nconst MAX_INSERT_PLAN_ICONS = 16;\n\nexport function positiveInteger(value: unknown, fallback: number): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n return Math.max(0, Math.floor(value));\n}\n\n/** Expand insert plans into their actual inventory-slot order and multiplicity. */\nexport function insertPlanSignals(items: BlueprintEntity[\"items\"]): AltSignal[] {\n if (!Array.isArray(items)) return [];\n const slotted: {\n signal: AltSignal;\n inventory: number;\n stack: number;\n order: number;\n }[] = [];\n const fallback: { signal: AltSignal; order: number }[] = [];\n let order = 0;\n\n for (const item of items) {\n const signal = asSignal(item.id);\n if (!signal) continue;\n const positions = Array.isArray(item.items?.in_inventory) ? item.items.in_inventory : [];\n if (positions.length > 0) {\n for (const position of positions) {\n const count = Math.min(positiveInteger(position.count, 1), MAX_INSERT_PLAN_ICONS);\n for (let i = 0; i < count; i++) {\n slotted.push({\n signal: { ...signal },\n inventory: Number.isFinite(position.inventory)\n ? position.inventory\n : Number.MAX_SAFE_INTEGER,\n stack: Number.isFinite(position.stack) ? position.stack : Number.MAX_SAFE_INTEGER,\n order: order++,\n });\n }\n }\n continue;\n }\n\n // `grid_count` is the 2.x equipment-grid shape and is also used by the 1.x\n // items-object migration. Preserve it as a compatibility fallback.\n const gridCount = positiveInteger(item.items?.grid_count, 0);\n const count = Math.min(gridCount > 0 ? gridCount : 1, MAX_INSERT_PLAN_ICONS);\n for (let i = 0; i < count; i++) fallback.push({ signal: { ...signal }, order: order++ });\n }\n\n slotted.sort((a, b) => a.inventory - b.inventory || a.stack - b.stack || a.order - b.order);\n return [...slotted.map((entry) => entry.signal), ...fallback.map((entry) => entry.signal)].slice(\n 0,\n MAX_INSERT_PLAN_ICONS,\n );\n}\n\n/** Extra gap between recipe and module rows on assemblers (tiles). */\nconst ASSEMBLER_INSERT_PLAN_Y_OFFSET = 0.2;\n/**\n * Visible request-pin size in tiles (36 px at the viewer’s default 64 ppt).\n */\nconst INSERT_PLAN_ICON_SCALE = 36 / 64;\n/** Edge-to-edge gap between visible pin chrome (~2 px at 64 ppt). */\nconst INSERT_PLAN_GAP_TILES = 2 / 64;\n\nexport function insertPlanLayout(count: number): { scale: number; xOffsets: number[] } {\n if (count <= 0) return { scale: 0, xOffsets: [] };\n const scale = INSERT_PLAN_ICON_SCALE;\n const step = scale + INSERT_PLAN_GAP_TILES;\n return {\n scale,\n xOffsets: Array.from({ length: count }, (_, i) => (i - (count - 1) / 2) * step),\n };\n}\n\n/**\n * Opaque pin height ÷ width from `item-request-slot` (a>20 bbox ≈ 44×62).\n * Used when estimating pin vertical extent for rolling-stock placement.\n */\nconst REQUEST_PIN_HEIGHT_OVER_WIDTH = 62 / 44;\n\n/**\n * Rolling-stock request-pin Y offset from entity center.\n *\n * Note: locomotive `icons_positioning.shift[1] = 0.3` and the IconSequencePositioning\n * default `0.7` are for inventory/burner alt-info, not item-request pins — using\n * those overshot. Empirically pins sit about half a pin-height below center.\n */\nexport function trainInsertPlanShiftY(pinSize: number): number {\n return (pinSize * REQUEST_PIN_HEIGHT_OVER_WIDTH) / 2;\n}\n\nexport function iconLayout(count: number, scale: number): [number, number][] {\n if (count <= 1) return [[0, 0]];\n if (count === 2)\n return [\n [-scale * 0.3, 0],\n [scale * 0.3, 0],\n ];\n const cols = Math.min(3, Math.ceil(Math.sqrt(count)));\n const rows = Math.ceil(count / cols);\n const spacing = scale * 0.62;\n const out: [number, number][] = [];\n for (let i = 0; i < count; i++) {\n const col = i % cols;\n const row = Math.floor(i / cols);\n out.push([(col - (cols - 1) / 2) * spacing, (row - (rows - 1) / 2) * spacing]);\n }\n return out;\n}\n\nexport function iconDrawSpec(def: EntityRenderDef) {\n return (\n def.iconDrawSpecification ?? {\n shift: [0, 0] as [number, number],\n scale: def.kind === \"inserter\" ? 0.5 : 0.75,\n scaleForMany: 0.5,\n renderLayer: \"entity-info-icon\" as const,\n }\n );\n}\n\n/**\n * Build insert-plan request-pin icons (sub 20–49). Always shown, not gated by alt mode.\n * Y matches the Factorio layout used when recipe/primary icons are present: pins sit\n * below those icons when the entity has primary signals, otherwise at the entity anchor.\n */\nexport function planRequestPinCommands(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n db: RenderDb,\n): IconCmd[] {\n const insertPlans = resolveAltSignals(db, insertPlanSignals(entity.items));\n if (insertPlans.length === 0) return [];\n\n const spec = iconDrawSpec(def);\n const pinBackingFrame = db.icons[\"utility/item-request-slot\"];\n const darkBackingFrame = db.icons[\"utility/entity-info-dark-background\"];\n const useRequestPin = pinBackingFrame !== undefined;\n const layer = RENDER_LAYERS[spec.renderLayer];\n const insertLayout = insertPlanLayout(insertPlans.length);\n\n // Rolling stock: request pins hang below entity center by ~half pin height.\n // Do not reuse icon_draw_specification (cargo badge) or icons_positioning\n // (burner alt-info) — those are different overlays.\n const insertAnchorY =\n def.kind === \"train\"\n ? entity.position.y + trainInsertPlanShiftY(insertLayout.scale)\n : entity.position.y + spec.shift[1];\n\n const primary = resolveAltSignals(db, entitySignals(entity, def));\n let insertY = insertAnchorY;\n if (primary.length > 0) {\n const primaryScale = primary.length > 1 ? spec.scaleForMany : spec.scale;\n const primaryOffsets = iconLayout(primary.length, primaryScale);\n const primaryBottom = primary.reduce((bottom, _entry, index) => {\n const y = entity.position.y + spec.shift[1] + (primaryOffsets[index]?.[1] ?? 0);\n return Math.max(bottom, y + primaryScale / 2);\n }, Number.NEGATIVE_INFINITY);\n const assemblerInsertYOffset = def.kind === \"assembler\" ? ASSEMBLER_INSERT_PLAN_Y_OFFSET : 0;\n insertY = primaryBottom + insertLayout.scale / 2 + assemblerInsertYOffset;\n }\n\n return insertPlans.map(({ frame }, index) => ({\n kind: \"icon\" as const,\n layer,\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: 20 + index,\n frame,\n x: entity.position.x + spec.shift[0] + (insertLayout.xOffsets[index] ?? 0),\n y: insertY,\n size: insertLayout.scale,\n ...(useRequestPin\n ? { backingFrame: pinBackingFrame, backingStyle: \"request-pin\" as const }\n : darkBackingFrame !== undefined\n ? { backingFrame: darkBackingFrame }\n : { backing: true }),\n }));\n}\n","/**\n * Decoded model for the Factorio 2.x blueprint string format.\n * Reference: https://wiki.factorio.com/Blueprint_string_format and the 2.1.11\n * runtime docs (BlueprintEntity, BlueprintWire).\n *\n * Design rules:\n * - Types are permissive: every object keeps an index signature so unknown or\n * future fields survive a decode -> encode round trip byte-for-byte (after\n * JSON canonicalization). The decoder must never drop fields it does not know.\n * - Field names mirror the JSON exactly (snake_case).\n */\n\nexport interface Color {\n r: number;\n g: number;\n b: number;\n a?: number;\n}\n\nexport interface Position {\n x: number;\n y: number;\n}\n\n/** A signal id used in icons, filters, and control behavior. */\nexport interface SignalId {\n name: string;\n /** \"item\" (default), \"fluid\", \"virtual\", \"entity\", \"recipe\", \"space-location\", \"asteroid-chunk\", \"quality\" */\n type?: string;\n quality?: string;\n [key: string]: unknown;\n}\n\nexport interface Icon {\n signal: SignalId;\n /** 1-based */\n index: number;\n [key: string]: unknown;\n}\n\n/** Item/signal filter shapes used by inventories, inserters, loaders, and splitters. */\nexport interface BlueprintFilter {\n index?: number;\n name?: string;\n quality?: string;\n comparator?: string;\n id?: SignalId;\n value?: SignalId;\n [key: string]: unknown;\n}\n\n/** One target stack for an item requested by a blueprint entity. */\nexport interface BlueprintInventoryPosition {\n inventory: number;\n /** Zero-based stack index. */\n stack: number;\n /** Number of items requested for this stack; defaults to 1. */\n count?: number;\n [key: string]: unknown;\n}\n\n/** Inventory/equipment-grid destinations for a requested blueprint item. */\nexport interface BlueprintItemInventoryPositions {\n in_inventory?: BlueprintInventoryPosition[];\n grid_count?: number;\n [key: string]: unknown;\n}\n\nexport interface BlueprintInsertPlan {\n id: SignalId;\n items?: BlueprintItemInventoryPositions;\n [key: string]: unknown;\n}\n\nexport interface BlueprintInventory {\n filters?: BlueprintFilter[];\n bar?: number;\n [key: string]: unknown;\n}\n\nexport interface Tile {\n name: string;\n /** Top-left corner of the tile. */\n position: Position;\n [key: string]: unknown;\n}\n\n/**\n * A wire connection (2.0 top-level format):\n * [source_entity_number, source_wire_connector_id, target_entity_number, target_wire_connector_id]\n * Connector ids follow defines.wire_connector_id (see wire-connectors.ts).\n */\nexport type BlueprintWire = [number, number, number, number];\n\n/**\n * Factorio 2.0 top-level rolling-stock coupling entry\n * (`BlueprintRollingStockConnection`).\n */\nexport interface BlueprintRollingStockConnection {\n /** entity_number of this rolling-stock piece. */\n stock: number;\n /** entity_number of the stock coupled to this piece's front joint. */\n front?: number;\n /** entity_number of the stock coupled to this piece's back joint. */\n back?: number;\n}\n\nexport interface BlueprintEntity {\n entity_number: number;\n name: string;\n /** Entity center, tile units. */\n position: Position;\n /** 16-way direction (0 = N, 4 = E, 8 = S, 12 = W). Absent means 0. */\n direction?: number;\n /** 2.0: flipped entity (splitters/refineries etc. in mirrored blueprints). */\n mirror?: boolean;\n quality?: string;\n /** Rolling stock / some rails: continuous orientation in [0, 1). */\n orientation?: number;\n /** Rolling stock / train-stop paint color (0–1 channels; some exports use 0–255). */\n color?: Color;\n recipe?: string;\n recipe_quality?: string;\n /** \"input\" | \"output\" for underground belts and loaders. */\n type?: string;\n /** Item requests (2.0 insert plans with inventory positions and/or equipment-grid count). */\n items?: BlueprintInsertPlan[];\n bar?: number;\n filters?: BlueprintFilter[];\n /** Inserter filter mode may be enabled even when no static filter is selected. */\n use_filters?: boolean;\n filter?: BlueprintFilter;\n filter_mode?: \"whitelist\" | \"blacklist\";\n input_priority?: \"left\" | \"right\" | \"none\";\n output_priority?: \"left\" | \"right\" | \"none\";\n \"priority-list\"?: BlueprintFilter[];\n \"chunk-filter\"?: BlueprintFilter[];\n fluid_filter?: string;\n request_filters?: Record<string, unknown>;\n inventory?: BlueprintInventory;\n trunk_inventory?: BlueprintInventory;\n ammo_inventory?: BlueprintInventory;\n burner_fuel_inventory?: BlueprintInventory;\n \"result-inventory\"?: BlueprintInventory;\n icon?: SignalId;\n control_behavior?: Record<string, unknown>;\n tags?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface Blueprint {\n item: \"blueprint\";\n label?: string;\n label_color?: Color;\n description?: string;\n icons?: Icon[];\n entities?: BlueprintEntity[];\n tiles?: Tile[];\n wires?: BlueprintWire[];\n schedules?: unknown[];\n /**\n * Factorio 2.0 rolling-stock coupling graph.\n * Each entry: which wagon (`stock`) and optional front/back neighbors by entity_number.\n */\n stock_connections?: BlueprintRollingStockConnection[];\n parameters?: unknown[];\n /** Encoded game version (major<<48 | minor<<32 | patch<<16). Fits in a JS number. */\n version: number;\n \"snap-to-grid\"?: Position;\n \"absolute-snapping\"?: boolean;\n \"position-relative-to-grid\"?: Position;\n [key: string]: unknown;\n}\n\n/** Book-slot wrappers: exactly one content key is present (unknown fields preserved). */\nexport type BlueprintBookEntry = {\n /** 0-based slot index. */\n index: number;\n [key: string]: unknown;\n} & (\n | {\n blueprint: Blueprint;\n blueprint_book?: never;\n upgrade_planner?: never;\n deconstruction_planner?: never;\n }\n | {\n blueprint_book: BlueprintBook;\n blueprint?: never;\n upgrade_planner?: never;\n deconstruction_planner?: never;\n }\n | {\n upgrade_planner: Record<string, unknown>;\n blueprint?: never;\n blueprint_book?: never;\n deconstruction_planner?: never;\n }\n | {\n deconstruction_planner: Record<string, unknown>;\n blueprint?: never;\n blueprint_book?: never;\n upgrade_planner?: never;\n }\n);\n\nexport interface BlueprintBook {\n item: \"blueprint-book\";\n label?: string;\n label_color?: Color;\n description?: string;\n icons?: Icon[];\n blueprints?: BlueprintBookEntry[];\n active_index?: number;\n version: number;\n [key: string]: unknown;\n}\n\n/**\n * Top-level decoded document: exactly one wrapper key is present.\n * Unknown extra fields are preserved for encode round-trips.\n */\nexport type BlueprintDocument = { [key: string]: unknown } & (\n | {\n blueprint: Blueprint;\n blueprint_book?: never;\n upgrade_planner?: never;\n deconstruction_planner?: never;\n }\n | {\n blueprint_book: BlueprintBook;\n blueprint?: never;\n upgrade_planner?: never;\n deconstruction_planner?: never;\n }\n | {\n upgrade_planner: Record<string, unknown>;\n blueprint?: never;\n blueprint_book?: never;\n deconstruction_planner?: never;\n }\n | {\n deconstruction_planner: Record<string, unknown>;\n blueprint?: never;\n blueprint_book?: never;\n upgrade_planner?: never;\n }\n);\n\n/** Flattened reference to a renderable blueprint inside a (possibly nested) book. */\nexport interface BlueprintRef {\n /** Book-entry index path from the root; [] when the root is a bare blueprint. */\n path: number[];\n label?: string;\n /** Nesting depth (0 = root). */\n depth: number;\n}\n\nexport function decodeVersion(v: number): {\n major: number;\n minor: number;\n patch: number;\n} {\n return {\n major: Math.floor(v / 2 ** 48) % 2 ** 16,\n minor: Math.floor(v / 2 ** 32) % 2 ** 16,\n patch: Math.floor(v / 2 ** 16) % 2 ** 16,\n };\n}\n","/**\n * Factorio 2.x `defines.wire_connector_id` numeric values used in blueprint\n * `wires` tuples: [src_entity, src_connector, dst_entity, dst_connector].\n *\n * Confirmed against runtime docs / wiki talk / draftsman (values are not unique\n * across names — circuit_red and combinator_input_red both equal 1).\n */\nexport const WIRE_CONNECTOR_ID = {\n circuit_red: 1,\n circuit_green: 2,\n combinator_input_red: 1,\n combinator_input_green: 2,\n combinator_output_red: 3,\n combinator_output_green: 4,\n pole_copper: 5,\n power_switch_left_copper: 5,\n power_switch_right_copper: 6,\n} as const;\n\nexport type WireColor = \"copper\" | \"red\" | \"green\";\n\n/**\n * Map a blueprint wire_connector_id to the drawn wire color.\n * Combinator output connectors use the same color as the matching input.\n */\nexport function wireConnectorColor(connectorId: number): WireColor | undefined {\n switch (connectorId) {\n case WIRE_CONNECTOR_ID.circuit_red:\n case WIRE_CONNECTOR_ID.combinator_output_red:\n return \"red\";\n case WIRE_CONNECTOR_ID.circuit_green:\n case WIRE_CONNECTOR_ID.combinator_output_green:\n return \"green\";\n case WIRE_CONNECTOR_ID.pole_copper:\n case WIRE_CONNECTOR_ID.power_switch_right_copper:\n return \"copper\";\n default:\n return undefined;\n }\n}\n","import {\n decodeVersion,\n type Blueprint,\n type BlueprintBook,\n type BlueprintBookEntry,\n type BlueprintDocument,\n type BlueprintEntity,\n type BlueprintInsertPlan,\n type BlueprintWire,\n} from \"./types/blueprint.js\";\nimport { WIRE_CONNECTOR_ID } from \"./wire-connectors.js\";\n\n/** Factorio 2.0+ major version encoded in blueprint `version` (major<<48). */\nconst FACTORIO_2_VERSION_MAJOR = 2 * 2 ** 48;\n\n/**\n * A single 1.x → 2.x transform. Adapters run only while the blueprint's\n * encoded version major is still < 2; after the pipeline, major is bumped\n * to 2 so re-entry is a no-op.\n */\nexport type BlueprintAdapter = {\n /** Stable id for docs / debugging (e.g. \"scale-legacy-directions\"). */\n id: string;\n apply(bp: Blueprint): Blueprint;\n};\n\n/**\n * Factorio 1.x encodes directions as 0/2/4/6 (N/E/S/W); 2.x uses 0/4/8/12.\n * @see https://wiki.factorio.com/Blueprint_string_format\n */\nconst scaleLegacyDirections: BlueprintAdapter = {\n id: \"scale-legacy-directions\",\n apply(bp) {\n if (!bp.entities?.length) return bp;\n return {\n ...bp,\n entities: bp.entities.map((e) =>\n e.direction == null ? e : { ...e, direction: (e.direction * 2) % 16 },\n ),\n };\n },\n};\n\n/**\n * Factorio 1.x stores module/item requests as `{ \"speed-module-3\": 2 }`.\n * 2.x uses an insert-plan array: `[{ id: { name, type }, items: { grid_count } }]`.\n */\nexport function legacyItemsObjectToInsertPlans(items: unknown): BlueprintInsertPlan[] | undefined {\n if (items == null) return undefined;\n if (Array.isArray(items)) return items as BlueprintInsertPlan[];\n if (typeof items !== \"object\") return undefined;\n const out: BlueprintInsertPlan[] = [];\n for (const [name, count] of Object.entries(items as Record<string, unknown>)) {\n if (!name) continue;\n const gridCount = typeof count === \"number\" && Number.isFinite(count) ? count : 1;\n out.push({\n id: { name, type: \"item\" },\n items: { grid_count: gridCount },\n });\n }\n return out;\n}\n\nconst itemsObjectToArray: BlueprintAdapter = {\n id: \"items-object-to-array\",\n apply(bp) {\n if (!bp.entities?.length) return bp;\n let changed = false;\n const entities = bp.entities.map((e) => {\n const raw = e.items as unknown;\n if (raw == null || Array.isArray(raw)) return e;\n if (typeof raw !== \"object\") return e;\n changed = true;\n const next: BlueprintEntity = {\n ...e,\n items: legacyItemsObjectToInsertPlans(raw),\n };\n return next;\n });\n return changed ? { ...bp, entities } : bp;\n },\n};\n\ntype LegacyConnectionLink = {\n entity_id?: unknown;\n circuit_id?: unknown;\n};\n\n/**\n * Map 1.x connection point (1=input/default, 2=output) + wire color to 2.x\n * `defines.wire_connector_id`.\n */\nfunction legacyCircuitConnectorId(point: number, color: \"red\" | \"green\"): number {\n if (point === 2) {\n return color === \"red\"\n ? WIRE_CONNECTOR_ID.combinator_output_red\n : WIRE_CONNECTOR_ID.combinator_output_green;\n }\n return color === \"red\" ? WIRE_CONNECTOR_ID.circuit_red : WIRE_CONNECTOR_ID.circuit_green;\n}\n\nfunction canonicalizeWire(wire: BlueprintWire): BlueprintWire {\n const [a, ac, b, bc] = wire;\n if (a < b || (a === b && ac <= bc)) return wire;\n return [b, bc, a, ac];\n}\n\nfunction wireKey(wire: BlueprintWire): string {\n const [a, ac, b, bc] = canonicalizeWire(wire);\n return `${a},${ac},${b},${bc}`;\n}\n\n/**\n * Factorio 1.x stores circuit links on each entity as `connections` and copper\n * pole links as `neighbours`. 2.x uses a single top-level `wires` array of\n * `[src, src_connector, dst, dst_connector]` tuples.\n *\n * @see https://wiki.factorio.com/Blueprint_string_format\n * @see https://wiki.factorio.com/Talk:Blueprint_string_format\n */\nconst connectionsNeighboursToWires: BlueprintAdapter = {\n id: \"connections-neighbours-to-wires\",\n apply(bp) {\n if (!bp.entities?.length) return bp;\n const seen = new Set<string>();\n const wires: BlueprintWire[] = [];\n\n const addWire = (wire: BlueprintWire) => {\n const key = wireKey(wire);\n if (seen.has(key)) return;\n seen.add(key);\n wires.push(canonicalizeWire(wire));\n };\n\n for (const existing of bp.wires ?? []) {\n if (Array.isArray(existing) && existing.length >= 4) {\n addWire([existing[0], existing[1], existing[2], existing[3]]);\n }\n }\n\n let converted = false;\n for (const entity of bp.entities) {\n const connections = (entity as { connections?: unknown }).connections;\n if (connections && typeof connections === \"object\") {\n for (const [pointKey, colors] of Object.entries(connections as Record<string, unknown>)) {\n const point = Number(pointKey);\n if (point !== 1 && point !== 2) continue;\n if (!colors || typeof colors !== \"object\") continue;\n for (const color of [\"red\", \"green\"] as const) {\n const links = (colors as Record<string, unknown>)[color];\n if (!Array.isArray(links)) continue;\n const srcConnector = legacyCircuitConnectorId(point, color);\n for (const link of links as LegacyConnectionLink[]) {\n const dstEntity = link?.entity_id;\n if (typeof dstEntity !== \"number\" || !Number.isFinite(dstEntity)) continue;\n const dstPoint =\n typeof link.circuit_id === \"number\" && Number.isFinite(link.circuit_id)\n ? link.circuit_id\n : 1;\n if (dstPoint !== 1 && dstPoint !== 2) continue;\n converted = true;\n addWire([\n entity.entity_number,\n srcConnector,\n dstEntity,\n legacyCircuitConnectorId(dstPoint, color),\n ]);\n }\n }\n }\n }\n\n const neighbours = (entity as { neighbours?: unknown }).neighbours;\n if (Array.isArray(neighbours)) {\n for (const neighbor of neighbours) {\n if (typeof neighbor !== \"number\" || !Number.isFinite(neighbor)) continue;\n converted = true;\n addWire([\n entity.entity_number,\n WIRE_CONNECTOR_ID.pole_copper,\n neighbor,\n WIRE_CONNECTOR_ID.pole_copper,\n ]);\n }\n }\n }\n\n if (!converted && wires.length === (bp.wires?.length ?? 0)) return bp;\n return { ...bp, wires };\n },\n};\n\n/**\n * Factorio 2.0 renames that appear in 1.x blueprint entity `name` fields.\n * Mirrors `base/migrations` entity maps plus the engine rail prototype rename\n * (`straight-rail`/`curved-rail` → `legacy-*`; new 2.0 rails reuse those names).\n *\n * Stack/bulk swap follows `1.2.0 stack inserter rename.json` (applied before\n * `2.0.0.json` in Factorio): 1.x `stack-inserter` becomes `bulk-inserter`.\n */\nconst LEGACY_ENTITY_RENAMES: Readonly<Record<string, string>> = {\n \"straight-rail\": \"legacy-straight-rail\",\n \"curved-rail\": \"legacy-curved-rail\",\n \"filter-inserter\": \"fast-inserter\",\n \"stack-filter-inserter\": \"bulk-inserter\",\n \"stack-inserter\": \"bulk-inserter\",\n \"logistic-chest-passive-provider\": \"passive-provider-chest\",\n \"logistic-chest-active-provider\": \"active-provider-chest\",\n \"logistic-chest-storage\": \"storage-chest\",\n \"logistic-chest-buffer\": \"buffer-chest\",\n \"logistic-chest-requester\": \"requester-chest\",\n};\n\nfunction renameLegacyEntityName(name: string): string {\n return LEGACY_ENTITY_RENAMES[name] ?? name;\n}\n\n/**\n * Rename 1.x entity prototype names to their 2.x equivalents so render-db\n * lookups succeed (and 1.x rails don't resolve to the new 2.0 rail protos).\n */\nconst renameLegacyEntities: BlueprintAdapter = {\n id: \"rename-legacy-entities\",\n apply(bp) {\n let changed = false;\n\n const entities = bp.entities?.map((e) => {\n const next = renameLegacyEntityName(e.name);\n if (next === e.name) return e;\n changed = true;\n return { ...e, name: next };\n });\n\n const icons = bp.icons?.map((icon) => {\n const signal = icon.signal;\n if (!signal?.name) return icon;\n const next = renameLegacyEntityName(signal.name);\n if (next === signal.name) return icon;\n changed = true;\n return { ...icon, signal: { ...signal, name: next } };\n });\n\n if (!changed) return bp;\n return {\n ...bp,\n ...(entities ? { entities } : {}),\n ...(icons ? { icons } : {}),\n };\n },\n};\n\n/**\n * Ordered adapter registry. Add new 1.x→2.x transforms here; document ids in\n * docs/CONTRACTS.md.\n */\nexport const BLUEPRINT_ADAPTERS: readonly BlueprintAdapter[] = [\n scaleLegacyDirections,\n itemsObjectToArray,\n connectionsNeighboursToWires,\n renameLegacyEntities,\n];\n\nfunction bumpVersionMajorTo2(version: number): number {\n return FACTORIO_2_VERSION_MAJOR + (version % 2 ** 48);\n}\n\n/**\n * Migrate a blueprint to Factorio 2.x shape for rendering.\n * Idempotent: 2.x (or already-migrated) blueprints are returned unchanged.\n */\nexport function migrateTo2x(bp: Blueprint): Blueprint {\n const ver = bp.version ?? 0;\n if (decodeVersion(ver).major >= 2) return bp;\n\n let out: Blueprint = { ...bp };\n for (const adapter of BLUEPRINT_ADAPTERS) {\n out = adapter.apply(out);\n }\n return { ...out, version: bumpVersionMajorTo2(ver) };\n}\n\nfunction migrateBookEntry(entry: BlueprintBookEntry): BlueprintBookEntry {\n if (\"blueprint\" in entry && entry.blueprint) {\n const { blueprint, ...rest } = entry;\n return { ...rest, index: entry.index, blueprint: migrateTo2x(blueprint) };\n }\n if (\"blueprint_book\" in entry && entry.blueprint_book) {\n const { blueprint_book, ...rest } = entry;\n return { ...rest, index: entry.index, blueprint_book: migrateBook(blueprint_book) };\n }\n return entry;\n}\n\nfunction migrateBook(book: BlueprintBook): BlueprintBook {\n const ver = book.version ?? 0;\n const entries = book.blueprints?.map(migrateBookEntry);\n return {\n ...book,\n ...(entries ? { blueprints: entries } : {}),\n version: decodeVersion(ver).major >= 2 ? ver : bumpVersionMajorTo2(ver),\n };\n}\n\n/**\n * Migrate every nested blueprint in a document (bare bp or book tree).\n * Planners are left untouched. Idempotent.\n */\nexport function migrateDocumentTo2x(doc: BlueprintDocument): BlueprintDocument {\n if (doc.blueprint) {\n return { ...doc, blueprint: migrateTo2x(doc.blueprint) };\n }\n if (doc.blueprint_book) {\n return { ...doc, blueprint_book: migrateBook(doc.blueprint_book) };\n }\n return doc;\n}\n","import type { BlueprintEntity } from \"../types/blueprint.js\";\nimport type { LayerGroup } from \"../types/render-db.js\";\n\nexport const DIR_DELTA: Record<0 | 4 | 8 | 12, [number, number]> = {\n 0: [0, -1],\n 4: [1, 0],\n 8: [0, 1],\n 12: [-1, 0],\n};\n\n/**\n * Map a 16-way blueprint direction to a layer variant index per the indexing\n * contract in render-db.ts.\n */\nexport function dir16ToIndex(direction: number, indexing: LayerGroup[\"indexing\"]): number {\n const d = ((direction % 16) + 16) % 16;\n switch (indexing) {\n case \"single\":\n return 0;\n case \"direction4\":\n return Math.floor(d / 4) % 4;\n case \"direction8\":\n return Math.floor(d / 2) % 8;\n case \"direction16\":\n return d;\n case \"resolver\":\n return 0;\n }\n}\n\nexport function cardinalDirection(direction: number | undefined): 0 | 4 | 8 | 12 {\n const d = direction ?? 0;\n const snapped = (Math.round(d / 4) * 4) % 16;\n if (snapped === 0 || snapped === 4 || snapped === 8 || snapped === 12) {\n return snapped;\n }\n return 0;\n}\n\nexport function opposite(dir: 0 | 4 | 8 | 12): 0 | 4 | 8 | 12 {\n return ((dir + 8) % 16) as 0 | 4 | 8 | 12;\n}\n\n/** Rotate a local (north-facing) offset by entity direction. */\nexport function rotateOffset(x: number, y: number, dir: 0 | 4 | 8 | 12): [number, number] {\n switch (dir) {\n case 0:\n return [x, y];\n case 4:\n return [-y, x];\n case 8:\n return [-x, -y];\n case 12:\n return [y, -x];\n }\n}\n\nexport function posKey(x: number, y: number): string {\n return `${Math.round(x * 1000) / 1000},${Math.round(y * 1000) / 1000}`;\n}\n\nexport type NeighborGrid = Map<string, BlueprintEntity[]>;\n\nexport function hasNeighbor(\n grid: NeighborGrid,\n x: number,\n y: number,\n predicate: (e: BlueprintEntity) => boolean,\n): boolean {\n const list = grid.get(posKey(x, y));\n if (!list) return false;\n return list.some(predicate);\n}\n\nexport function buildNeighborGrid(entities: BlueprintEntity[]): NeighborGrid {\n const grid: NeighborGrid = new Map();\n for (const e of entities) {\n const key = posKey(e.position.x, e.position.y);\n const list = grid.get(key);\n if (list) list.push(e);\n else grid.set(key, [e]);\n }\n return grid;\n}\n","import type { Blueprint, BlueprintEntity } from \"../types/blueprint.js\";\nimport type { EntityKind, EntityRenderDef, RenderDb } from \"../types/render-db.js\";\nimport {\n DIR_DELTA,\n cardinalDirection,\n dir16ToIndex,\n opposite,\n posKey,\n rotateOffset,\n} from \"./shared.js\";\n\n/**\n * Verified against belt_animation_set defaults: X=east_index-1=0,\n * west_index-1=1, north_index-1=2, south_index-1=3.\n * Prototype defaults are 1-based; values here are 0-based rows into the 20-slot table.\n */\nexport const BELT_STRAIGHT_INDEX: Record<0 | 4 | 8 | 12, number> = {\n 0: 2,\n 4: 0,\n 8: 3,\n 12: 1,\n};\n\n/** Curve when the sole feeder is on the belt's right (FBE \"right\"). */\nexport const BELT_CURVE_RIGHT: Record<0 | 4 | 8 | 12, number> = {\n 0: 4, // east_to_north\n 4: 8, // south_to_east\n 8: 11, // west_to_south\n 12: 7, // north_to_west\n};\n\n/** Curve when the sole feeder is on the belt's left (FBE \"left\"). */\nexport const BELT_CURVE_LEFT: Record<0 | 4 | 8 | 12, number> = {\n 0: 6, // west_to_north\n 4: 5, // north_to_east\n 8: 9, // east_to_south\n 12: 10, // south_to_west\n};\n\n/**\n * Starting-cap row for a belt facing `dir`.\n * FBE maps north-facing → starting_south (back-edge art), etc.\n */\nexport const BELT_START_INDEX: Record<0 | 4 | 8 | 12, number> = {\n 0: 12, // starting_south\n 4: 14, // starting_west\n 8: 16, // starting_north\n 12: 18, // starting_east\n};\n\n/** Ending-cap row for a belt facing `dir`. */\nexport const BELT_END_INDEX: Record<0 | 4 | 8 | 12, number> = {\n 0: 17, // ending_north\n 4: 19, // ending_east\n 8: 13, // ending_south\n 12: 15, // ending_west\n};\n\nconst BELT_CONNECTABLE: ReadonlySet<EntityKind> = new Set([\n \"belt\",\n \"underground-belt\",\n \"splitter\",\n \"loader\",\n]);\n\n/**\n * UG/loader structure sheets pack horizontal columns N,E,S,W (same as direction4).\n * Kept as an explicit table so distill/resolve stay aligned if packing changes.\n * Outputs use the opposite flow direction so paired hoods face away from each other\n * (same-column direction_in/direction_out art faces the same way).\n */\nexport const UG_STRUCTURE_INDEX: readonly [number, number, number, number] = [0, 1, 2, 3];\n\n/** Structure column for UG/loader hood sprites (object layer only). */\nexport function undergroundStructureIndex(\n direction: number,\n type: BlueprintEntity[\"type\"],\n): number {\n const dir4 = dir16ToIndex(direction, \"direction4\");\n const structureDir4 = type === \"output\" ? (dir4 + 2) % 4 : dir4;\n return UG_STRUCTURE_INDEX[structureDir4] ?? structureDir4;\n}\n\nexport interface BeltOccupant {\n entity: BlueprintEntity;\n def: EntityRenderDef;\n}\n\n/**\n * Map every occupied tile-center to belt-connectable entities on that tile.\n * Splitters cover two tiles (tileSize [2,1] = long × short; 1×2 when facing N/S).\n */\nexport function buildBeltTileIndex(\n entities: BlueprintEntity[],\n db: RenderDb,\n): Map<string, BeltOccupant[]> {\n const index = new Map<string, BeltOccupant[]>();\n\n const add = (x: number, y: number, occ: BeltOccupant) => {\n const key = posKey(x, y);\n const list = index.get(key);\n if (list) list.push(occ);\n else index.set(key, [occ]);\n };\n\n for (const entity of entities) {\n const def = db.entities[entity.name];\n if (!def || !BELT_CONNECTABLE.has(def.kind)) continue;\n const occ: BeltOccupant = { entity, def };\n\n if (def.kind === \"splitter\") {\n const dir = cardinalDirection(entity.direction);\n const raw = def.data?.tileSize;\n // tileSize is the north-facing footprint (wide × short). N/S stay [2,1];\n // E/W rotate to [1,2] — matches Factorio collision and structure art.\n const baseW = raw?.[0] ?? 2;\n const baseH = raw?.[1] ?? 1;\n const w = dir === 0 || dir === 8 ? baseW : baseH;\n const h = dir === 0 || dir === 8 ? baseH : baseW;\n const cx = entity.position.x;\n const cy = entity.position.y;\n for (let ix = 0; ix < w; ix++) {\n for (let iy = 0; iy < h; iy++) {\n add(cx - w / 2 + 0.5 + ix, cy - h / 2 + 0.5 + iy, occ);\n }\n }\n } else {\n add(entity.position.x, entity.position.y, occ);\n }\n }\n return index;\n}\n\n/**\n * Neighbors in absolute NESW order, then rotated so index 0 = ahead of `dir`.\n * Matches FBE getNeighbourData + splice(direction/4): [ahead, right, behind, left].\n */\nfunction rotatedNeighbors(\n beltIndex: Map<string, BeltOccupant[]>,\n x: number,\n y: number,\n dir: 0 | 4 | 8 | 12,\n): (BeltOccupant | undefined)[] {\n const abs: (BeltOccupant | undefined)[] = [\n beltIndex.get(posKey(x, y - 1))?.[0],\n beltIndex.get(posKey(x + 1, y))?.[0],\n beltIndex.get(posKey(x, y + 1))?.[0],\n beltIndex.get(posKey(x - 1, y))?.[0],\n ];\n const start = dir / 4;\n return [abs[start], abs[(start + 1) % 4], abs[(start + 2) % 4], abs[(start + 3) % 4]];\n}\n\n/**\n * True when the occupant faces toward the belt (FBE C2).\n * Underground/loader inputs never count as feeders.\n */\nfunction facesTowardBelt(occ: BeltOccupant | undefined, absRelDir: 0 | 4 | 8 | 12): boolean {\n if (!occ) return false;\n if (\n (occ.def.kind === \"underground-belt\" || occ.def.kind === \"loader\") &&\n occ.entity.type === \"input\"\n ) {\n return false;\n }\n return cardinalDirection(occ.entity.direction) === opposite(absRelDir);\n}\n\nexport function beltCurveIndex(\n entity: BlueprintEntity,\n beltIndex: Map<string, BeltOccupant[]>,\n): number {\n const dir = cardinalDirection(entity.direction);\n const { x, y } = entity.position;\n const C = rotatedNeighbors(beltIndex, x, y, dir);\n const absDirs: (0 | 4 | 8 | 12)[] = [\n dir,\n ((dir + 4) % 16) as 0 | 4 | 8 | 12,\n opposite(dir),\n ((dir + 12) % 16) as 0 | 4 | 8 | 12,\n ];\n const C2 = C.map((occ, i) => {\n const abs = absDirs[i];\n return abs !== undefined && facesTowardBelt(occ, abs) ? occ : undefined;\n });\n\n // Exactly one perpendicular input and no input from behind → curve.\n if (C2[1] && !C2[3] && !C2[2]) return BELT_CURVE_RIGHT[dir];\n if (C2[3] && !C2[1] && !C2[2]) return BELT_CURVE_LEFT[dir];\n return BELT_STRAIGHT_INDEX[dir];\n}\n\n/**\n * Circuit-connector topology variation for a transport belt (0–6).\n * Factorio order: X, H, V, SE, SW, NE, NW.\n *\n * Uses the same neighbor model as beltCurveIndex. Both perpendicular feeders → X;\n * straight belts → H (E/W) or V (N/S); curves map via belt animation corner names.\n */\nexport function beltCircuitConnectorVariation(\n entity: BlueprintEntity,\n beltIndex: Map<string, BeltOccupant[]>,\n): number {\n const dir = cardinalDirection(entity.direction);\n const { x, y } = entity.position;\n const C = rotatedNeighbors(beltIndex, x, y, dir);\n const absDirs: (0 | 4 | 8 | 12)[] = [\n dir,\n ((dir + 4) % 16) as 0 | 4 | 8 | 12,\n opposite(dir),\n ((dir + 12) % 16) as 0 | 4 | 8 | 12,\n ];\n const C2 = C.map((occ, i) => {\n const abs = absDirs[i];\n return abs !== undefined && facesTowardBelt(occ, abs) ? occ : undefined;\n });\n\n // Both sides feeding (T / cross) → X.\n if (C2[1] && C2[3]) return 0;\n\n if (C2[1] && !C2[3] && !C2[2]) {\n return BELT_CURVE_ANIM_TO_CONNECTOR[BELT_CURVE_RIGHT[dir]] ?? 0;\n }\n if (C2[3] && !C2[1] && !C2[2]) {\n return BELT_CURVE_ANIM_TO_CONNECTOR[BELT_CURVE_LEFT[dir]] ?? 0;\n }\n\n // Straight: H for east/west, V for north/south.\n return dir === 4 || dir === 12 ? 1 : 2;\n}\n\n/**\n * Map belt animation curve row → connector variation (SE=3, SW=4, NE=5, NW=6).\n * Animation names like east_to_north share the NE corner of the tile.\n */\nconst BELT_CURVE_ANIM_TO_CONNECTOR: Record<number, number> = {\n 4: 5, // east_to_north → NE\n 5: 5, // north_to_east → NE\n 6: 6, // west_to_north → NW\n 7: 6, // north_to_west → NW\n 8: 3, // south_to_east → SE\n 9: 3, // east_to_south → SE\n 10: 4, // south_to_west → SW\n 11: 4, // west_to_south → SW\n};\n\n/** Back-patch row for connector variation: straights/X → 0; SE/SW → 1; NE/NW → 2. */\nexport function beltConnectorBackPatchIndex(variation: number): number {\n if (variation <= 2) return 0;\n if (variation <= 4) return 1;\n return 2;\n}\n\n/**\n * Belt-reader sheet layout (Factorio binary validation):\n * - bands (rows): StraightSolidBand=0, StraightOpenBand=1, CurvedSolidBand=2, Ending=3\n * - frames: North=0, East=1, South=2, West=3 (tile-edge pieces)\n */\nexport const BELT_READER_BAND = {\n solid: 0,\n open: 1,\n curved: 2,\n ending: 3,\n} as const;\n\nexport const BELT_READER_FRAME = {\n north: 0,\n east: 1,\n south: 2,\n west: 3,\n} as const;\n\nconst BELT_READER_FRAME_FROM_DIR: Record<0 | 4 | 8 | 12, number> = {\n 0: BELT_READER_FRAME.north,\n 4: BELT_READER_FRAME.east,\n 8: BELT_READER_FRAME.south,\n 12: BELT_READER_FRAME.west,\n};\n\n/** Map circuit-connector corner (SE=3,SW=4,NE=5,NW=6) → reader frame N/E/S/W. */\nconst CONNECTOR_CORNER_TO_READER_FRAME: Record<number, number> = {\n 5: BELT_READER_FRAME.north, // NE — arc along north+east\n 3: BELT_READER_FRAME.east, // SE\n 4: BELT_READER_FRAME.south, // SW\n 6: BELT_READER_FRAME.west, // NW — arc along west+north\n};\n\nexport type BeltReaderSlot = {\n band: number;\n frame: number;\n /** Mirror Ending across the open tip so the outer half of the fancy cap appears. */\n flipX?: boolean;\n flipY?: boolean;\n /**\n * Extra tile-space shift on top of the sprite variant shift.\n * Used to hang the mirrored Ending half past the open tip.\n */\n shift?: [number, number];\n};\n\n/**\n * Ending cells are authored as inward hooks flush to the open edge (no outer\n * half). Mirror across that edge into the adjacent tile so the cap closes.\n */\nfunction endingMirrorSlot(frame: number): BeltReaderSlot {\n switch (frame) {\n case BELT_READER_FRAME.east:\n return { band: BELT_READER_BAND.ending, frame, flipX: true, shift: [1, 0] };\n case BELT_READER_FRAME.west:\n return { band: BELT_READER_BAND.ending, frame, flipX: true, shift: [-1, 0] };\n case BELT_READER_FRAME.north:\n return { band: BELT_READER_BAND.ending, frame, flipY: true, shift: [0, -1] };\n case BELT_READER_FRAME.south:\n return { band: BELT_READER_BAND.ending, frame, flipY: true, shift: [0, 1] };\n default:\n return { band: BELT_READER_BAND.ending, frame };\n }\n}\n\n/**\n * Which belt-reader sheet cells to paint for one belt on an entire_belt_hold line.\n * Straights: SolidBand on both long-side edges; open line ends also get Ending\n * short-edge caps so the rail \"grabs\" the belt tip (in-game).\n * Curves: one CurvedSolidBand corner frame.\n *\n * Ending sprites are inward hooks flush to the tip edge — also emit a mirrored\n * copy one tile past the tip so the outer half of the fancy cap appears.\n */\nexport function beltReaderSlots(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n beltIndex: Map<string, BeltOccupant[]>,\n readerEntities: Set<number>,\n): BeltReaderSlot[] {\n const dir = cardinalDirection(entity.direction);\n const curve = beltCurveIndex(entity, beltIndex);\n const isCurve = curve >= 4 && curve <= 11;\n\n if (isCurve) {\n const corner = BELT_CURVE_ANIM_TO_CONNECTOR[curve] ?? 5;\n const frame = CONNECTOR_CORNER_TO_READER_FRAME[corner] ?? BELT_READER_FRAME.north;\n return [{ band: BELT_READER_BAND.curved, frame }];\n }\n\n // Long sides: E/W-facing → N+S; N/S-facing → E+W.\n const sides =\n dir === 4 || dir === 12\n ? [BELT_READER_FRAME.north, BELT_READER_FRAME.south]\n : [BELT_READER_FRAME.east, BELT_READER_FRAME.west];\n\n const slots: BeltReaderSlot[] = sides.map((frame) => ({\n band: BELT_READER_BAND.solid,\n frame,\n }));\n\n // Terminus caps: Ending frame + mirrored outer half past the open tip\n // (through UGs still counts as connected).\n const forward = nextOnLine(entity, def, dir, beltIndex);\n const backward = nextOnLine(entity, def, opposite(dir), beltIndex);\n const forwardInLine = forward != null && readerEntities.has(forward.entity_number);\n const backwardInLine = backward != null && readerEntities.has(backward.entity_number);\n const pushEnding = (frame: number) => {\n slots.push({ band: BELT_READER_BAND.ending, frame });\n slots.push(endingMirrorSlot(frame));\n };\n if (!forwardInLine) pushEnding(BELT_READER_FRAME_FROM_DIR[dir]);\n if (!backwardInLine) pushEnding(BELT_READER_FRAME_FROM_DIR[opposite(dir)]);\n\n return slots;\n}\n\n/** `defines.control_behavior.transport_belt.content_read_mode.entire_belt_hold` */\nexport const BELT_CONTENT_READ_ENTIRE = 2;\n\n/** Enable/disable (write/output) — horizontal red/green LEDs on the belt cage. */\nexport function isBeltCircuitOutputEnabled(entity: BlueprintEntity): boolean {\n const cb = entity.control_behavior;\n if (!cb) return false;\n // 2.x blueprint field; accept legacy enable_disable if present\n return cb.circuit_enabled === true || cb.circuit_enable_disable === true;\n}\n\n/** Read belt contents (input) — vertical blue LED on the belt cage. */\nexport function isBeltCircuitInputEnabled(entity: BlueprintEntity): boolean {\n return entity.control_behavior?.circuit_read_hand_contents === true;\n}\n\n/**\n * Connector-frame state used by Factorio's four-frame belt connector sheet.\n * The frames are a behavior bitmask, not belt directions:\n * none=0, enable/output=1, read/input=2, both=3.\n */\nexport function beltCircuitConnectorFrame(entity: BlueprintEntity): number {\n return (isBeltCircuitOutputEnabled(entity) ? 1 : 0) | (isBeltCircuitInputEnabled(entity) ? 2 : 0);\n}\n\nfunction isEntireBeltHold(entity: BlueprintEntity): boolean {\n const cb = entity.control_behavior;\n if (!cb || cb.circuit_read_hand_contents !== true) return false;\n return cb.circuit_contents_read_mode === BELT_CONTENT_READ_ENTIRE;\n}\n\n/**\n * Belts that should show whole-belt-reader skirts: the wired reader with\n * entire_belt_hold, plus every transport-belt and underground-belt on its\n * contiguous line (through UGs; stops at splitters / side-loads).\n */\nexport function collectBeltReaderEntities(\n bp: Blueprint,\n db: RenderDb,\n beltIndex: Map<string, BeltOccupant[]>,\n): Set<number> {\n const out = new Set<number>();\n const entities = bp.entities ?? [];\n for (const e of entities) {\n const def = db.entities[e.name];\n if (!def || def.kind !== \"belt\") continue;\n if (!isEntireBeltHold(e)) continue;\n for (const id of walkTransportLine(e, beltIndex, db)) out.add(id);\n }\n return out;\n}\n\n/**\n * Walk a transport line from `start` in both directions.\n * Includes plain belts and underground belts (skirts draw under UG hoods);\n * UG also bridges the walk. Stops at splitters / true side-loads.\n */\nfunction walkTransportLine(\n start: BlueprintEntity,\n beltIndex: Map<string, BeltOccupant[]>,\n db: RenderDb,\n): number[] {\n const ids: number[] = [];\n const seen = new Set<number>();\n const queue: BlueprintEntity[] = [start];\n\n while (queue.length > 0) {\n const cur = queue.pop();\n if (!cur || seen.has(cur.entity_number)) continue;\n seen.add(cur.entity_number);\n const def = db.entities[cur.name];\n if (!def) continue;\n\n if (def.kind === \"belt\" || def.kind === \"underground-belt\") {\n ids.push(cur.entity_number);\n }\n\n if (def.kind === \"belt\" || def.kind === \"underground-belt\") {\n const dir = cardinalDirection(cur.direction);\n const forward = nextOnLine(cur, def, dir, beltIndex);\n const backward = nextOnLine(cur, def, opposite(dir), beltIndex);\n if (forward) queue.push(forward);\n if (backward) queue.push(backward);\n // Curve corner: also walk onto the perpendicular feeder belt.\n if (def.kind === \"belt\") {\n const feeder = curvePerpendicularFeeder(cur, beltIndex);\n if (feeder) queue.push(feeder);\n }\n }\n }\n return ids;\n}\n\n/**\n * If `entity` is a curve, the single perpendicular belt feeding into it.\n */\nfunction curvePerpendicularFeeder(\n entity: BlueprintEntity,\n beltIndex: Map<string, BeltOccupant[]>,\n): BlueprintEntity | undefined {\n const dir = cardinalDirection(entity.direction);\n const { x, y } = entity.position;\n const C = rotatedNeighbors(beltIndex, x, y, dir);\n const absDirs: (0 | 4 | 8 | 12)[] = [\n dir,\n ((dir + 4) % 16) as 0 | 4 | 8 | 12,\n opposite(dir),\n ((dir + 12) % 16) as 0 | 4 | 8 | 12,\n ];\n const C2 = C.map((occ, i) => {\n const abs = absDirs[i];\n return abs !== undefined && facesTowardBelt(occ, abs) ? occ : undefined;\n });\n if (C2[1] && !C2[3] && !C2[2]) return C2[1]?.entity;\n if (C2[3] && !C2[1] && !C2[2]) return C2[3]?.entity;\n return undefined;\n}\n\n/**\n * Next entity along a transport line in absolute direction `stepDir`.\n * Skips through underground pairs; rejects splitters / true side-loads.\n * Allows stepping onto a curve when we are that curve's perpendicular feeder.\n */\nfunction nextOnLine(\n cur: BlueprintEntity,\n curDef: EntityRenderDef,\n stepDir: 0 | 4 | 8 | 12,\n beltIndex: Map<string, BeltOccupant[]>,\n): BlueprintEntity | undefined {\n if (curDef.kind === \"underground-belt\") {\n const facing = cardinalDirection(cur.direction);\n const isOutput = cur.type === \"output\";\n // Into the tunnel → jump to partner.\n if ((!isOutput && stepDir === facing) || (isOutput && stepDir === opposite(facing))) {\n return findUndergroundPartner(cur, beltIndex) ?? undefined;\n }\n // Out of the open side → neighbor belt/UG in stepDir (fall through).\n }\n\n const [dx, dy] = DIR_DELTA[stepDir];\n const occupants = beltIndex.get(posKey(cur.position.x + dx, cur.position.y + dy));\n if (!occupants?.length) return undefined;\n\n for (const occ of occupants) {\n if (occ.def.kind === \"splitter\") return undefined; // line breaks\n if (occ.def.kind === \"belt\" || occ.def.kind === \"underground-belt\") {\n const od = cardinalDirection(occ.entity.direction);\n if (od === stepDir || od === opposite(stepDir)) return occ.entity;\n // Non-collinear: only OK when the neighbor is a curve and we are its feeder\n // (same transport line around the corner). True side-loads stop here.\n if (occ.def.kind === \"belt\") {\n const feeder = curvePerpendicularFeeder(occ.entity, beltIndex);\n if (feeder && feeder.entity_number === cur.entity_number) return occ.entity;\n }\n return undefined;\n }\n }\n return undefined;\n}\n\nfunction findUndergroundPartner(\n ug: BlueprintEntity,\n beltIndex: Map<string, BeltOccupant[]>,\n): BlueprintEntity | null {\n const facing = cardinalDirection(ug.direction);\n const isOutput = ug.type === \"output\";\n // Search along the tunnel: from input, forward; from output, backward.\n const step = isOutput ? opposite(facing) : facing;\n const [dx, dy] = DIR_DELTA[step];\n const maxDist = 10; // vanilla max UG distance is tier-dependent; 10 covers turbo\n for (let i = 1; i <= maxDist; i++) {\n const x = ug.position.x + dx * i;\n const y = ug.position.y + dy * i;\n const occupants = beltIndex.get(posKey(x, y));\n if (!occupants) continue;\n for (const occ of occupants) {\n if (occ.def.kind !== \"underground-belt\") continue;\n if (occ.entity.name !== ug.name) continue;\n if (cardinalDirection(occ.entity.direction) !== facing) continue;\n const partnerIsOutput = occ.entity.type === \"output\";\n if (partnerIsOutput === isOutput) continue; // need opposite type\n return occ.entity;\n }\n }\n return null;\n}\n\nexport function hasBeltFeederAt(\n x: number,\n y: number,\n dir: 0 | 4 | 8 | 12,\n beltIndex: Map<string, BeltOccupant[]>,\n): boolean {\n const C = rotatedNeighbors(beltIndex, x, y, dir);\n const absDirs: (0 | 4 | 8 | 12)[] = [\n dir,\n ((dir + 4) % 16) as 0 | 4 | 8 | 12,\n opposite(dir),\n ((dir + 12) % 16) as 0 | 4 | 8 | 12,\n ];\n for (let i = 1; i < 4; i++) {\n const abs = absDirs[i];\n if (abs !== undefined && facesTowardBelt(C[i], abs)) return true;\n }\n return false;\n}\n\nexport function hasBeltFeeder(\n entity: BlueprintEntity,\n beltIndex: Map<string, BeltOccupant[]>,\n): boolean {\n return hasBeltFeederAt(\n entity.position.x,\n entity.position.y,\n cardinalDirection(entity.direction),\n beltIndex,\n );\n}\n\n/**\n * True when something feeds the UG/loader open side (behind the facing).\n * Side-loads do not seal the open half — only a behind feeder suppresses the\n * start wrap cap.\n */\nexport function hasOpenSideFeeder(\n entity: BlueprintEntity,\n beltIndex: Map<string, BeltOccupant[]>,\n): boolean {\n const dir = cardinalDirection(entity.direction);\n const { x, y } = entity.position;\n const C = rotatedNeighbors(beltIndex, x, y, dir);\n return facesTowardBelt(C[2], opposite(dir));\n}\n\n/**\n * True when a belt-connectable ahead accepts this belt's output\n * (no ending cap). Belts and splitters always accept; UG/loader inputs\n * facing the same direction accept; UG/loader outputs do not.\n */\nexport function hasBeltConsumerAt(\n x: number,\n y: number,\n dir: 0 | 4 | 8 | 12,\n beltIndex: Map<string, BeltOccupant[]>,\n): boolean {\n const [dx, dy] = DIR_DELTA[dir];\n const occupants = beltIndex.get(posKey(x + dx, y + dy));\n if (!occupants) return false;\n\n for (const occ of occupants) {\n if (occ.def.kind === \"belt\" || occ.def.kind === \"splitter\") return true;\n if (occ.def.kind === \"underground-belt\" || occ.def.kind === \"loader\") {\n if (occ.entity.type === \"output\") continue;\n if (cardinalDirection(occ.entity.direction) === dir) return true;\n }\n }\n return false;\n}\n\nexport function hasBeltConsumer(\n entity: BlueprintEntity,\n beltIndex: Map<string, BeltOccupant[]>,\n): boolean {\n return hasBeltConsumerAt(\n entity.position.x,\n entity.position.y,\n cardinalDirection(entity.direction),\n beltIndex,\n );\n}\n\n/** Full-tile shift behind (start) / ahead (end) for belt caps — matches FBE. */\nexport function beltCapShift(dir: 0 | 4 | 8 | 12, kind: \"start\" | \"end\"): [number, number] {\n // FBE: start = rotate([0, 1], dir), end = rotate([0, -1], dir).\n return kind === \"start\" ? rotateOffset(0, 1, dir) : rotateOffset(0, -1, dir);\n}\n","/**\n * Electric-pole facing from wire topology (FBE WireConnections.getPowerPoleDirection).\n * Factorio auto-orients poles from connections; blueprints often omit `direction`.\n */\n\nimport type { Blueprint, BlueprintEntity } from \"./types/blueprint.js\";\n\nexport interface Point2 {\n x: number;\n y: number;\n}\n\n/** Angle of point relative to centre, degrees CCW from +X (FBE util.getAngle). */\nexport function getAngle(cX: number, cY: number, pX: number, pY: number): number {\n const x = pX - cX;\n const y = pY - cY;\n if (x === 0 && y === 0) return 0;\n const angle = (Math.acos(x / Math.sqrt(x * x + y * y)) * 180) / Math.PI;\n if (y < 0) return 360 - angle;\n return angle;\n}\n\nfunction angleToSector(angle: number): 0 | 1 | 2 | 3 {\n const cwAngle = 360 - angle;\n const sectorAngle = 360 / 8;\n const offset = sectorAngle * 1.5;\n let newAngle = cwAngle - offset;\n if (Math.sign(newAngle) === -1) {\n newAngle = 360 + newAngle;\n }\n const sector = Math.floor(newAngle / sectorAngle);\n return (sector % 4) as 0 | 1 | 2 | 3;\n}\n\n/**\n * Average neighbor bearings into a cardinal direction 0|4|8|12 (FBE).\n * Y is inverted to match Factorio's screen-space angle convention.\n */\nexport function powerPoleRotationFromNeighbors(centre: Point2, points: Point2[]): number {\n if (points.length === 0) return 0;\n const sectorSum = points\n .map((p) => getAngle(0, 0, p.x - centre.x, (p.y - centre.y) * -1))\n .map(angleToSector)\n .reduce((acc, sec) => acc + sec, 0 as number);\n return Math.floor(sectorSum / points.length) * 4;\n}\n\n/**\n * Neighbor entity numbers connected to `entityNumber` by any wire in `bp.wires`.\n */\nexport function wireNeighborNumbers(bp: Blueprint, entityNumber: number): number[] {\n const wires = bp.wires;\n if (!wires?.length) return [];\n const out: number[] = [];\n for (const w of wires) {\n if (!Array.isArray(w) || w.length < 4) continue;\n const [a, , b] = w;\n if (a === entityNumber) out.push(b);\n else if (b === entityNumber) out.push(a);\n }\n return out;\n}\n\n/**\n * Effective pole direction: explicit blueprint `direction` when set, else FBE\n * inference from wire-neighbor positions. Returns 0|4|8|12 (or 0 if alone).\n */\nexport function effectivePowerPoleDirection(\n entity: BlueprintEntity,\n bp: Blueprint,\n byNumber: Map<number, BlueprintEntity>,\n): number {\n if (entity.direction !== undefined && entity.direction !== null) {\n return ((entity.direction % 16) + 16) % 16;\n }\n const neighborNums = wireNeighborNumbers(bp, entity.entity_number);\n if (neighborNums.length === 0) return 0;\n const points: Point2[] = [];\n for (const n of neighborNums) {\n const other = byNumber.get(n);\n if (other) points.push(other.position);\n }\n if (points.length === 0) return 0;\n return powerPoleRotationFromNeighbors(entity.position, points);\n}\n\n/**\n * Precompute effective directions for every electric-pole entity in the blueprint.\n */\nexport function buildPowerPoleDirections(\n bp: Blueprint,\n entities: BlueprintEntity[],\n isElectricPole: (entity: BlueprintEntity) => boolean,\n): Map<number, number> {\n const byNumber = new Map(entities.map((e) => [e.entity_number, e]));\n const out = new Map<number, number>();\n for (const e of entities) {\n if (!isElectricPole(e)) continue;\n out.set(e.entity_number, effectivePowerPoleDirection(e, bp, byNumber));\n }\n return out;\n}\n","import type { BlueprintEntity } from \"../types/blueprint.js\";\nimport type { RenderDb } from \"../types/render-db.js\";\nimport {\n DIR_DELTA,\n type NeighborGrid,\n cardinalDirection,\n hasNeighbor,\n opposite,\n posKey,\n} from \"./shared.js\";\n\ninterface HeatPortOccupant {\n entityNumber: number;\n direction: 0 | 4 | 8 | 12;\n}\n\ntype HeatPortGrid = Map<string, HeatPortOccupant[]>;\n\n/** Outward cardinal direction of a distilled heat-connection target offset. */\nexport function heatPortDirection(ox: number, oy: number): 0 | 4 | 8 | 12 {\n if (Math.abs(ox) >= Math.abs(oy)) return ox >= 0 ? 4 : 12;\n return oy >= 0 ? 8 : 0;\n}\n\n/**\n * Index the source tile and facing of every heat port. `heatConnections` stores\n * the adjacent target tile, so step one tile inward to recover the source.\n */\nexport function buildHeatPortGrid(entities: BlueprintEntity[], db: RenderDb): HeatPortGrid {\n const ports: HeatPortGrid = new Map();\n for (const entity of entities) {\n const def = db.entities[entity.name];\n const connections = def?.data?.heatConnections;\n if (!connections) continue;\n const d = cardinalDirection(entity.direction);\n for (const [ox, oy] of connections[String(d)] ?? []) {\n const direction = heatPortDirection(ox, oy);\n const [dx, dy] = DIR_DELTA[direction];\n const key = posKey(entity.position.x + ox - dx, entity.position.y + oy - dy);\n const list = ports.get(key);\n const occupant = { entityNumber: entity.entity_number, direction };\n if (list) list.push(occupant);\n else ports.set(key, [occupant]);\n }\n }\n return ports;\n}\n\nexport function heatPortConnected(\n entity: BlueprintEntity,\n targetOffset: [number, number],\n heatPorts: HeatPortGrid,\n grid: NeighborGrid,\n db: RenderDb,\n): boolean {\n const [ox, oy] = targetOffset;\n const direction = heatPortDirection(ox, oy);\n const targetX = entity.position.x + ox;\n const targetY = entity.position.y + oy;\n if (hasNeighbor(grid, targetX, targetY, (n) => db.entities[n.name]?.kind === \"heat-pipe\")) {\n return true;\n }\n return (heatPorts.get(posKey(targetX, targetY)) ?? []).some(\n (port) => port.entityNumber !== entity.entity_number && port.direction === opposite(direction),\n );\n}\n\n/**\n * Map: pipe-tile-key → set of NESW sides (\"n\"|\"e\"|\"s\"|\"w\") that connect to a\n * non-pipe fluid entity via fluidConnections.\n */\nexport function buildFluidPipeSides(\n entities: BlueprintEntity[],\n db: RenderDb,\n): Map<string, Set<string>> {\n const map = new Map<string, Set<string>>();\n for (const entity of entities) {\n const def = db.entities[entity.name];\n if (!def?.data?.fluidConnections) continue;\n if (def.kind === \"pipe\") continue;\n const fc = def.data.fluidConnections;\n const d = cardinalDirection(entity.direction);\n // Re-derive facing from offset: side = dominant axis from entity center to pipe tile.\n for (const [ox, oy] of fc[String(d)] ?? []) {\n const pipeX = entity.position.x + ox;\n const pipeY = entity.position.y + oy;\n const pk = posKey(pipeX, pipeY);\n // Direction from pipe back toward entity center.\n const dx = entity.position.x - pipeX;\n const dy = entity.position.y - pipeY;\n let side: string;\n if (Math.abs(dx) >= Math.abs(dy)) {\n side = dx > 0 ? \"e\" : \"w\";\n } else {\n side = dy > 0 ? \"s\" : \"n\";\n }\n let set = map.get(pk);\n if (!set) {\n set = new Set();\n map.set(pk, set);\n }\n set.add(side);\n }\n }\n return map;\n}\n\n/**\n * Map: heat-pipe-tile-key -> NESW sides that connect to a non-heat-pipe\n * entity via heatConnections. Large heat entities are indexed by their actual\n * port tile because their entity center is not necessarily adjacent to it.\n */\nexport function buildHeatPipeSides(\n entities: BlueprintEntity[],\n db: RenderDb,\n): Map<string, Set<string>> {\n const map = new Map<string, Set<string>>();\n for (const entity of entities) {\n const def = db.entities[entity.name];\n if (!def?.data?.heatConnections || def.kind === \"heat-pipe\") continue;\n const d = cardinalDirection(entity.direction);\n for (const [ox, oy] of def.data.heatConnections[String(d)] ?? []) {\n const pipeX = entity.position.x + ox;\n const pipeY = entity.position.y + oy;\n const pk = posKey(pipeX, pipeY);\n const dx = entity.position.x - pipeX;\n const dy = entity.position.y - pipeY;\n const side = Math.abs(dx) >= Math.abs(dy) ? (dx > 0 ? \"e\" : \"w\") : dy > 0 ? \"s\" : \"n\";\n let set = map.get(pk);\n if (!set) {\n set = new Set();\n map.set(pk, set);\n }\n set.add(side);\n }\n }\n return map;\n}\n\nexport function pipeMask(\n entity: BlueprintEntity,\n grid: NeighborGrid,\n db: RenderDb,\n fluidPipeSides: Map<string, Set<string>>,\n): string {\n const { x, y } = entity.position;\n const check = (nx: number, ny: number, side: string): boolean => {\n if (hasNeighbor(grid, nx, ny, (n) => db.entities[n.name]?.kind === \"pipe\")) {\n return true;\n }\n if (fluidPipeSides.get(posKey(x, y))?.has(side)) return true;\n\n const neighbors = grid.get(posKey(nx, ny));\n if (neighbors) {\n for (const n of neighbors) {\n const nd = db.entities[n.name];\n if (!nd) continue;\n if (nd.protoType === \"pipe-to-ground\" || n.name === \"pipe-to-ground\") {\n const openDir = cardinalDirection(n.direction);\n const [dx, dy] = DIR_DELTA[openDir];\n if (Math.abs(n.position.x + dx - x) < 0.01 && Math.abs(n.position.y + dy - y) < 0.01) {\n return true;\n }\n }\n const fc = nd.data?.fluidConnections;\n if (fc) {\n const d = cardinalDirection(n.direction);\n for (const [ox, oy] of fc[String(d)] ?? []) {\n if (Math.abs(n.position.x + ox - x) < 0.01 && Math.abs(n.position.y + oy - y) < 0.01) {\n return true;\n }\n }\n }\n }\n }\n return false;\n };\n const n = check(x, y - 1, \"n\") ? \"1\" : \"0\";\n const e = check(x + 1, y, \"e\") ? \"1\" : \"0\";\n const s = check(x, y + 1, \"s\") ? \"1\" : \"0\";\n const w = check(x - 1, y, \"w\") ? \"1\" : \"0\";\n return `${n}${e}${s}${w}`;\n}\n\nexport function heatPipeMask(\n entity: BlueprintEntity,\n grid: NeighborGrid,\n db: RenderDb,\n heatPipeSides: Map<string, Set<string>>,\n): string {\n const { x, y } = entity.position;\n const check = (nx: number, ny: number, side: string): boolean => {\n if (heatPipeSides.get(posKey(x, y))?.has(side)) return true;\n const neighbors = grid.get(posKey(nx, ny));\n if (!neighbors) return false;\n for (const n of neighbors) {\n const nd = db.entities[n.name];\n if (!nd) continue;\n if (nd.kind === \"heat-pipe\") return true;\n const hc = nd.data?.heatConnections;\n if (!hc) continue;\n const d = cardinalDirection(n.direction);\n for (const [ox, oy] of hc[String(d)] ?? []) {\n if (Math.abs(n.position.x + ox - x) < 0.01 && Math.abs(n.position.y + oy - y) < 0.01) {\n return true;\n }\n }\n }\n return false;\n };\n const n = check(x, y - 1, \"n\") ? \"1\" : \"0\";\n const e = check(x + 1, y, \"e\") ? \"1\" : \"0\";\n const s = check(x, y + 1, \"s\") ? \"1\" : \"0\";\n const w = check(x - 1, y, \"w\") ? \"1\" : \"0\";\n return `${n}${e}${s}${w}`;\n}\n","import { buildPowerPoleDirections } from \"../pole-orientation.js\";\nimport type { Blueprint, BlueprintEntity } from \"../types/blueprint.js\";\nimport type { EntityRenderDef, RenderDb } from \"../types/render-db.js\";\nimport { type BeltOccupant, buildBeltTileIndex } from \"./belts.js\";\nimport { buildFluidPipeSides, buildHeatPipeSides } from \"./pipes.js\";\nimport { type NeighborGrid, buildNeighborGrid } from \"./shared.js\";\n\nexport interface LayerSelection {\n /** Index into def.graphics. */\n group: number;\n variantKey: string;\n index: number;\n /**\n * Extra tile-space shift applied on top of the sprite variant's shift\n * (used for belt starting/ending caps).\n */\n shift?: [number, number];\n}\n\nexport interface ResolvedEntity {\n entity: BlueprintEntity;\n def: EntityRenderDef;\n selections: LayerSelection[];\n}\n\nexport interface ResolveOptions {\n /** Emit belt starting/ending cap selections. Default true. */\n beltEndings?: boolean;\n}\n\n/** Shared neighbor indexes for one blueprint planning pass. */\nexport interface ResolveContext {\n blueprint: Blueprint;\n db: RenderDb;\n entities: BlueprintEntity[];\n grid: NeighborGrid;\n beltIndex: Map<string, BeltOccupant[]>;\n fluidPipeSides: Map<string, Set<string>>;\n /** Heat-pipe tile -> sides connected to a non-heat-pipe entity's heat port. */\n heatPipeSides?: Map<string, Set<string>>;\n poleDirs: Map<number, number>;\n /** Use platform cargo-bay body/connection art (hub or space-platform tiles). */\n preferPlatformGraphics: boolean;\n}\n\n/** Space-platform hub or foundation tiles → use platform cargo-bay art. */\nexport function blueprintPrefersPlatformGraphics(\n blueprint: Blueprint,\n entities: BlueprintEntity[] = blueprint.entities ?? [],\n): boolean {\n if (entities.some((e) => e.name === \"space-platform-hub\")) return true;\n return (blueprint.tiles ?? []).some((t) => t.name.startsWith(\"space-platform-\"));\n}\n\n/** Build indexes for an already migrated blueprint. */\nexport function createResolveContext(blueprint: Blueprint, db: RenderDb): ResolveContext {\n const entities = blueprint.entities ?? [];\n const grid = buildNeighborGrid(entities);\n const beltIndex = buildBeltTileIndex(entities, db);\n const fluidPipeSides = buildFluidPipeSides(entities, db);\n const heatPipeSides = buildHeatPipeSides(entities, db);\n const poleDirs = buildPowerPoleDirections(\n blueprint,\n entities,\n (entity) => db.entities[entity.name]?.protoType === \"electric-pole\",\n );\n const preferPlatformGraphics = blueprintPrefersPlatformGraphics(blueprint, entities);\n return {\n blueprint,\n db,\n entities,\n grid,\n beltIndex,\n fluidPipeSides,\n heatPipeSides,\n poleDirs,\n preferPlatformGraphics,\n };\n}\n","import type { BlueprintEntity } from \"../types/blueprint.js\";\nimport type { RenderDb } from \"../types/render-db.js\";\nimport { type NeighborGrid, cardinalDirection, hasNeighbor } from \"./shared.js\";\n\n/**\n * Factorio only authors south-extending wall pieces (corner_*_down, straight_vertical,\n * t_up, …). A north link is drawn by the northern neighbour’s south-reaching sprite,\n * so picture choice depends on E/S/W only.\n */\nexport function wallPictureKey(e: boolean, s: boolean, w: boolean): string {\n if (s) {\n if (e && w) return \"0111\"; // t_up\n if (e) return \"0110\"; // corner_right_down\n if (w) return \"0011\"; // corner_left_down\n return \"1010\"; // straight_vertical\n }\n if (e && w) return \"0101\"; // straight_horizontal\n if (e) return \"0100\"; // ending_right\n if (w) return \"0001\"; // ending_left\n return \"0000\"; // single\n}\n\nexport function wallMask(entity: BlueprintEntity, grid: NeighborGrid, db: RenderDb): string {\n const { x, y } = entity.position;\n const pred = (n: BlueprintEntity) => {\n const nd = db.entities[n.name];\n return nd?.kind === \"wall\" || nd?.kind === \"gate\";\n };\n const e = hasNeighbor(grid, x + 1, y, pred);\n const s = hasNeighbor(grid, x, y + 1, pred);\n const w = hasNeighbor(grid, x - 1, y, pred);\n return wallPictureKey(e, s, w);\n}\n\nexport function gateVariantKey(entity: BlueprintEntity): string {\n const dir = cardinalDirection(entity.direction);\n // Horizontal gate when facing N/S (spans E-W); vertical when facing E/W.\n return dir === 0 || dir === 8 ? \"horizontal\" : \"vertical\";\n}\n","import { migrateTo2x } from \"../migrate.js\";\nimport type { Blueprint, BlueprintEntity } from \"../types/blueprint.js\";\nimport type { EntityRenderDef, LayerGroup, RenderDb } from \"../types/render-db.js\";\nimport {\n BELT_END_INDEX,\n BELT_START_INDEX,\n type BeltOccupant,\n beltCapShift,\n beltCurveIndex,\n hasBeltConsumer,\n hasBeltConsumerAt,\n hasBeltFeeder,\n hasBeltFeederAt,\n hasOpenSideFeeder,\n undergroundStructureIndex,\n} from \"./belts.js\";\nimport {\n type LayerSelection,\n type ResolveContext,\n type ResolveOptions,\n type ResolvedEntity,\n createResolveContext,\n} from \"./context.js\";\nimport {\n buildHeatPipeSides,\n buildHeatPortGrid,\n heatPortConnected,\n heatPortDirection,\n heatPipeMask,\n pipeMask,\n} from \"./pipes.js\";\nimport {\n DIR_DELTA,\n type NeighborGrid,\n cardinalDirection,\n dir16ToIndex,\n rotateOffset,\n} from \"./shared.js\";\nimport {\n artilleryCannonShift,\n projectTrainOrientation,\n projectVehicleOrientation,\n trainOrientationIndex,\n trainRailShiftY,\n trainWheelShifts,\n} from \"./trains.js\";\nimport { gateVariantKey, wallMask } from \"./walls.js\";\n\nexport {\n BELT_CONTENT_READ_ENTIRE,\n BELT_CURVE_LEFT,\n BELT_CURVE_RIGHT,\n BELT_END_INDEX,\n BELT_READER_BAND,\n BELT_READER_FRAME,\n BELT_START_INDEX,\n BELT_STRAIGHT_INDEX,\n UG_STRUCTURE_INDEX,\n type BeltOccupant,\n type BeltReaderSlot,\n beltCircuitConnectorFrame,\n beltCircuitConnectorVariation,\n beltConnectorBackPatchIndex,\n beltReaderSlots,\n buildBeltTileIndex,\n collectBeltReaderEntities,\n isBeltCircuitInputEnabled,\n isBeltCircuitOutputEnabled,\n undergroundStructureIndex,\n} from \"./belts.js\";\nexport {\n type LayerSelection,\n type ResolveContext,\n type ResolveOptions,\n type ResolvedEntity,\n blueprintPrefersPlatformGraphics,\n createResolveContext,\n} from \"./context.js\";\nexport { cardinalDirection, dir16ToIndex, rotateOffset } from \"./shared.js\";\nexport {\n artilleryCannonShift,\n projectTrainOrientation,\n projectVehicleOrientation,\n railDirectionIndex,\n trainOrientationIndex,\n trainRailShiftY,\n trainWheelShifts,\n} from \"./trains.js\";\n\nfunction variantKeyFor(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n grid: NeighborGrid,\n db: RenderDb,\n fluidPipeSides: Map<string, Set<string>>,\n heatPipeSides: Map<string, Set<string>>,\n opts?: { preferPlatformGraphics?: boolean },\n): string {\n switch (def.kind) {\n case \"underground-belt\":\n case \"loader\":\n return entity.type === \"output\" ? \"out\" : \"in\";\n case \"pipe\":\n return pipeMask(entity, grid, db, fluidPipeSides);\n case \"heat-pipe\":\n return heatPipeMask(entity, grid, db, heatPipeSides);\n case \"wall\":\n return wallMask(entity, grid, db);\n case \"gate\":\n return gateVariantKey(entity);\n default:\n if (\n opts?.preferPlatformGraphics &&\n def.graphics.some((g) => g.variants.platform !== undefined)\n ) {\n return \"platform\";\n }\n return \"default\";\n }\n}\n\nfunction indexFor(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n group: LayerGroup,\n beltIndex: Map<string, BeltOccupant[]>,\n poleDirs?: Map<number, number>,\n): number {\n if (def.kind === \"vehicle\") {\n const n =\n (typeof def.data?.orientationCount === \"number\" && def.data.orientationCount > 0\n ? def.data.orientationCount\n : group.variants.default?.length) ?? 1;\n return trainOrientationIndex(projectVehicleOrientation(entity.orientation ?? 0), n);\n }\n if (def.kind === \"train\") {\n const n =\n (typeof def.data?.orientationCount === \"number\" && def.data.orientationCount > 0\n ? def.data.orientationCount\n : group.variants.default?.length) ?? 1;\n const projected = projectTrainOrientation(entity.orientation ?? 0);\n const groupIndex = def.graphics.indexOf(group);\n const isWheels =\n typeof def.data?.wheelsGroupIndex === \"number\" && groupIndex === def.data.wheelsGroupIndex;\n // Cargo/fluid wagon bodies use back_equals_front; wheel sheets do not.\n return trainOrientationIndex(projected, n, def.data?.backEqualsFront === true && !isWheels);\n }\n const direction =\n def.protoType === \"electric-pole\" && poleDirs?.has(entity.entity_number)\n ? (poleDirs.get(entity.entity_number) ?? 0)\n : (entity.direction ?? 0);\n if (group.indexing === \"resolver\") {\n if (def.kind === \"belt\") {\n return beltCurveIndex(entity, beltIndex);\n }\n return dir16ToIndex(direction, \"direction4\");\n }\n if (\n (group.layer === \"object\" || group.layer === \"object-under\") &&\n (def.kind === \"underground-belt\" || def.kind === \"loader\") &&\n group.indexing === \"direction4\"\n ) {\n return undergroundStructureIndex(entity.direction ?? 0, entity.type);\n }\n // Inserter platform sheet faces the drop side; FBE samples ((dir+8)%16)/4.\n // Hands use entity facing (pickup). Platform is always graphics[0].\n if (def.kind === \"inserter\" && group.indexing === \"direction4\" && def.graphics[0] === group) {\n return (dir16ToIndex(entity.direction ?? 0, \"direction4\") + 2) % 4;\n }\n return dir16ToIndex(direction, group.indexing);\n}\n\nexport function resolveWithContext(\n context: ResolveContext,\n warningsOut?: string[],\n opts?: ResolveOptions,\n): ResolvedEntity[] {\n const beltEndings = opts?.beltEndings ?? true;\n const { beltIndex, db, entities, fluidPipeSides, grid, poleDirs, preferPlatformGraphics } =\n context;\n const heatPipeSides = context.heatPipeSides ?? buildHeatPipeSides(entities, db);\n const heatPorts = buildHeatPortGrid(entities, db);\n const out: ResolvedEntity[] = [];\n\n for (const entity of entities) {\n const def = db.entities[entity.name];\n if (!def) {\n warningsOut?.push(`Unknown entity \"${entity.name}\" (entity_number=${entity.entity_number})`);\n continue;\n }\n\n const variantKey = variantKeyFor(entity, def, grid, db, fluidPipeSides, heatPipeSides, {\n preferPlatformGraphics,\n });\n const selections: LayerSelection[] = [];\n\n for (let group = 0; group < def.graphics.length; group++) {\n const layerGroup = def.graphics[group];\n if (!layerGroup) continue;\n\n if (def.data?.heatConnectionPatchGroupIndices?.includes(group)) {\n const d = cardinalDirection(entity.direction);\n for (const [portIndex, targetOffset] of (\n def.data.heatConnections?.[String(d)] ?? []\n ).entries()) {\n const direction = heatPortDirection(targetOffset[0], targetOffset[1]);\n const [dx, dy] = DIR_DELTA[direction];\n selections.push({\n group,\n variantKey: heatPortConnected(entity, targetOffset, heatPorts, grid, db)\n ? \"connected\"\n : \"disconnected\",\n index: portIndex,\n shift: [targetOffset[0] - dx, targetOffset[1] - dy],\n });\n }\n continue;\n }\n\n const index = indexFor(entity, def, layerGroup, beltIndex, poleDirs);\n const key =\n layerGroup.variants[variantKey] !== undefined\n ? variantKey\n : layerGroup.variants.default !== undefined\n ? \"default\"\n : variantKey;\n\n // Rolling stock: two bogies at ±jointDistance/2 (not a single centered sprite).\n if (def.kind === \"train\" && group === def.data?.wheelsGroupIndex) {\n const joint =\n typeof def.data?.jointDistance === \"number\" && def.data.jointDistance > 0\n ? def.data.jointDistance\n : 4;\n const n =\n (typeof def.data?.orientationCount === \"number\" && def.data.orientationCount > 0\n ? def.data.orientationCount\n : layerGroup.variants.default?.length) ?? 1;\n for (const bogie of trainWheelShifts(entity.orientation ?? 0, joint)) {\n selections.push({\n group,\n variantKey: key,\n index: trainOrientationIndex(bogie.orientation, n),\n shift: bogie.shift,\n });\n }\n continue;\n }\n\n // Splitters: two lane underlays at ±0.5 perpendicular to facing (FBE),\n // plus start/end caps per lane when that side is open.\n if (def.kind === \"splitter\" && layerGroup.layer === \"transport-belt\") {\n const dir = cardinalDirection(entity.direction);\n const dir4 = dir16ToIndex(entity.direction ?? 0, \"direction4\");\n const lanes: [number, number][] = [rotateOffset(-0.5, 0, dir), rotateOffset(0.5, 0, dir)];\n for (const lane of lanes) {\n selections.push({\n group,\n variantKey: key,\n index,\n shift: lane,\n });\n if (!beltEndings) continue;\n const lx = entity.position.x + lane[0];\n const ly = entity.position.y + lane[1];\n if (layerGroup.variants.start && !hasBeltFeederAt(lx, ly, dir, beltIndex)) {\n const [sx, sy] = beltCapShift(dir, \"start\");\n selections.push({\n group,\n variantKey: \"start\",\n index: dir4,\n shift: [lane[0] + sx, lane[1] + sy],\n });\n }\n if (layerGroup.variants.end && !hasBeltConsumerAt(lx, ly, dir, beltIndex)) {\n const [ex, ey] = beltCapShift(dir, \"end\");\n selections.push({\n group,\n variantKey: \"end\",\n index: dir4,\n shift: [lane[0] + ex, lane[1] + ey],\n });\n }\n }\n continue;\n }\n\n // UG/loader: straight underlay + open-side wrap cap when that side is open\n // (no behind feeder into an input / no consumer after an output). Side-loads\n // do not seal the open half. Connected open sides stay continuous — no cap.\n if (\n (def.kind === \"underground-belt\" || def.kind === \"loader\") &&\n layerGroup.layer === \"transport-belt\"\n ) {\n selections.push({ group, variantKey: key, index });\n if (beltEndings) {\n const dir = cardinalDirection(entity.direction);\n const dir4 = dir16ToIndex(entity.direction ?? 0, \"direction4\");\n const isOutput = entity.type === \"output\";\n if (!isOutput && layerGroup.variants.start && !hasOpenSideFeeder(entity, beltIndex)) {\n selections.push({\n group,\n variantKey: \"start\",\n index: dir4,\n shift: beltCapShift(dir, \"start\"),\n });\n }\n if (isOutput && layerGroup.variants.end && !hasBeltConsumer(entity, beltIndex)) {\n selections.push({\n group,\n variantKey: \"end\",\n index: dir4,\n shift: beltCapShift(dir, \"end\"),\n });\n }\n }\n continue;\n }\n\n if (def.kind === \"train\") {\n const railY = trainRailShiftY(entity.orientation ?? 0);\n const cannonIdxs = def.data?.cannonGroupIndices;\n if (Array.isArray(cannonIdxs) && cannonIdxs.includes(group)) {\n const [cx, cy] = artilleryCannonShift(entity.orientation ?? 0, {\n cannonBaseHeight:\n typeof def.data?.cannonBaseHeight === \"number\"\n ? def.data.cannonBaseHeight\n : undefined,\n cannonBaseShiftWhenVertical:\n typeof def.data?.cannonBaseShiftWhenVertical === \"number\"\n ? def.data.cannonBaseShiftWhenVertical\n : undefined,\n cannonBaseShiftWhenHorizontal:\n typeof def.data?.cannonBaseShiftWhenHorizontal === \"number\"\n ? def.data.cannonBaseShiftWhenHorizontal\n : undefined,\n orientationCount:\n typeof def.data?.orientationCount === \"number\"\n ? def.data.orientationCount\n : undefined,\n });\n selections.push({\n group,\n variantKey: key,\n index,\n shift: [cx, cy + railY],\n });\n } else {\n selections.push({ group, variantKey: key, index, shift: [0, railY] });\n }\n continue;\n }\n\n selections.push({ group, variantKey: key, index });\n\n if (\n beltEndings &&\n def.kind === \"belt\" &&\n layerGroup.indexing === \"resolver\" &&\n (layerGroup.variants[key]?.length ?? 0) >= 20\n ) {\n const dir = cardinalDirection(entity.direction);\n if (!hasBeltFeeder(entity, beltIndex)) {\n selections.push({\n group,\n variantKey: key,\n index: BELT_START_INDEX[dir],\n shift: beltCapShift(dir, \"start\"),\n });\n }\n if (!hasBeltConsumer(entity, beltIndex)) {\n selections.push({\n group,\n variantKey: key,\n index: BELT_END_INDEX[dir],\n shift: beltCapShift(dir, \"end\"),\n });\n }\n }\n }\n\n out.push({ entity, def, selections });\n }\n\n return out;\n}\n\nexport function resolve(bp: Blueprint, db: RenderDb, opts?: ResolveOptions): ResolveResult {\n const warnings: string[] = [];\n const entities = resolveWithContext(createResolveContext(migrateTo2x(bp), db), warnings, opts);\n return { entities, warnings };\n}\n\nexport interface ResolveResult {\n entities: ResolvedEntity[];\n warnings: string[];\n}\n","import { iconDrawSpec, iconLayout, insertPlanSignals } from \"./alt-mode-request-pin.js\";\nimport {\n altSignalFrame,\n entitySignals,\n filterSignals,\n isSplitterType,\n resolveAltSignals,\n splitterLaneFilter,\n type ResolvedAltSignal,\n} from \"./alt-mode-signals.js\";\nimport { cardinalDirection } from \"./resolve.js\";\nimport type { BlueprintEntity } from \"./types/blueprint.js\";\nimport { RENDER_LAYERS, type IconCmd } from \"./types/draw-list.js\";\nimport type { EntityRenderDef, RenderDb } from \"./types/render-db.js\";\n\nexport { planRequestPinCommands } from \"./alt-mode-request-pin.js\";\nexport { altSignalFrame, signalIconKeys } from \"./alt-mode-signals.js\";\n\n/**\n * Entity corner quality badge size in tiles when `quality_indicator_scale` is 1\n * (3-tile entities).\n */\nconst ENTITY_QUALITY_BADGE_TILES = 0.5;\n/**\n * Quality overlay on alt-info signal icons, as a fraction of the parent icon size.\n * (Separate from the selection-box entity badge.)\n */\nconst QUALITY_SIGNAL_OVERLAY_FRACTION = 0.5;\n\n/** Factorio default: shorter tile span / 3, clamped to [0.5, 1]. Size 3 → scale 1. */\nfunction qualityIndicatorScale(def: EntityRenderDef): number {\n if (typeof def.qualityIndicatorScale === \"number\" && Number.isFinite(def.qualityIndicatorScale)) {\n return def.qualityIndicatorScale;\n }\n const [[x1, y1], [x2, y2]] = def.collisionBox;\n const tw = Math.max(1, Math.ceil(Math.abs(x2 - x1) - 1e-6));\n const th = Math.max(1, Math.ceil(Math.abs(y2 - y1) - 1e-6));\n return Math.min(1, Math.max(0.5, Math.min(tw, th) / 3));\n}\n\nfunction qualityBadgeCommands(\n resolved: ResolvedAltSignal[],\n parents: IconCmd[],\n entityNumber: number,\n db: RenderDb,\n startSub: number,\n): IconCmd[] {\n const commands: IconCmd[] = [];\n for (let index = 0; index < resolved.length; index++) {\n const quality = resolved[index]?.signal.quality;\n if (!quality || quality === \"normal\") continue;\n const frame = db.icons[`quality/${quality}`] ?? db.icons[\"utility/missing-icon\"];\n const parent = parents[index];\n if (frame === undefined || !parent) continue;\n commands.push({\n kind: \"icon\",\n layer: RENDER_LAYERS[\"entity-info-icon-above\"],\n sortY: 0,\n sortX: 0,\n entity: entityNumber,\n sub: startSub + index,\n frame,\n x: parent.x - parent.size * 0.3,\n y: parent.y + parent.size * 0.3,\n size: parent.size * QUALITY_SIGNAL_OVERLAY_FRACTION,\n });\n }\n return commands;\n}\n\nfunction swapPriority(\n priority: BlueprintEntity[\"input_priority\"],\n mirrored: boolean | undefined,\n): BlueprintEntity[\"input_priority\"] {\n if (!mirrored || priority === \"none\" || priority == null) return priority;\n return priority === \"left\" ? \"right\" : \"left\";\n}\n\nfunction splitterPriorityCommands(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n db: RenderDb,\n startSub: number,\n): IconCmd[] {\n if (!isSplitterType(def)) return [];\n const arrowFrame = db.icons[\"utility/indication-arrow\"];\n const direction = cardinalDirection(entity.direction ?? 0);\n const angle = direction * 22.5;\n const radians = (angle * Math.PI) / 180;\n const forward: [number, number] = [Math.sin(radians), -Math.cos(radians)];\n const right: [number, number] = [Math.cos(radians), Math.sin(radians)];\n // Both arrows point along belt travel (indication-arrow faces north at 0°).\n // Side inset keeps indicators on the splitter body (not on adjacent belt tiles).\n // Lane offset stays half-tile so arrows sit on the belt centerlines.\n // Filter icons stay on the entity centerline with a full half-tile lane shift.\n const ARROW_SIDE_OFFSET = 0.25;\n const ARROW_LANE_OFFSET = 0.5;\n const FILTER_LANE_OFFSET = 0.5;\n const specs: { priority: BlueprintEntity[\"input_priority\"]; side: -1 | 1 }[] = [\n { priority: swapPriority(entity.input_priority, entity.mirror), side: -1 },\n { priority: swapPriority(entity.output_priority, entity.mirror), side: 1 },\n ];\n const filterSignal = splitterLaneFilter(entity, def);\n const filterFrame = filterSignal\n ? (altSignalFrame(db, filterSignal) ?? db.icons[\"utility/missing-icon\"])\n : undefined;\n const darkBackingFrame = db.icons[\"utility/entity-info-dark-background\"];\n const filterSize = iconDrawSpec(def).scale;\n const commands: IconCmd[] = [];\n for (const spec of specs) {\n if (!spec.priority || spec.priority === \"none\") continue;\n const lane = spec.priority === \"right\" ? 1 : -1;\n const useFilter = spec.side > 0 && filterFrame !== undefined;\n // Arrows: inset on body. Filters: entity centerline + priority lane half.\n const sideOffset = useFilter ? 0 : ARROW_SIDE_OFFSET;\n const laneOffset = useFilter ? FILTER_LANE_OFFSET : ARROW_LANE_OFFSET;\n const x =\n entity.position.x + forward[0] * sideOffset * spec.side + right[0] * laneOffset * lane;\n const y =\n entity.position.y + forward[1] * sideOffset * spec.side + right[1] * laneOffset * lane;\n\n if (useFilter) {\n const filterCmd: IconCmd = {\n kind: \"icon\",\n layer: RENDER_LAYERS[\"entity-info-icon-above\"],\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: startSub + commands.length,\n frame: filterFrame,\n x,\n y,\n size: filterSize,\n ...(darkBackingFrame !== undefined\n ? { backingFrame: darkBackingFrame }\n : { backing: true }),\n };\n commands.push(filterCmd);\n if (entity.filter_mode === \"blacklist\") {\n const blacklistFrame = db.icons[\"utility/filter-blacklist\"];\n if (blacklistFrame !== undefined) {\n commands.push({\n kind: \"icon\",\n layer: RENDER_LAYERS[\"entity-info-icon-above\"],\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: startSub + commands.length,\n frame: blacklistFrame,\n x: filterCmd.x + filterCmd.size * 0.28,\n y: filterCmd.y + filterCmd.size * 0.28,\n size: filterCmd.size * 0.45,\n });\n }\n }\n continue;\n }\n\n if (arrowFrame === undefined) continue;\n const arrowSize = db.iconScales?.[\"utility/indication-arrow\"];\n if (arrowSize === undefined) continue;\n commands.push({\n kind: \"icon\",\n layer: RENDER_LAYERS[\"entity-info-icon-above\"],\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: startSub + commands.length,\n frame: arrowFrame,\n x,\n y,\n size: arrowSize,\n rotation: angle,\n });\n }\n return commands;\n}\n\nfunction isDirectionalCombinator(def: EntityRenderDef): boolean {\n return (\n def.protoType === \"arithmetic-combinator\" ||\n def.protoType === \"decider-combinator\" ||\n def.protoType === \"selector-combinator\"\n );\n}\n\n/** Input/output flow arrows shown at both ends of directional combinators. */\nfunction combinatorFlowCommands(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n db: RenderDb,\n): IconCmd[] {\n if (!isDirectionalCombinator(def)) return [];\n const frame = db.icons[\"utility/indication-arrow\"];\n const spriteScale = db.iconScales?.[\"utility/indication-arrow\"];\n if (frame === undefined || spriteScale === undefined) return [];\n // The prototype scale applies to a 64 px source; Factorio's visible triangle\n // occupies roughly half a tile once transparent padding is accounted for.\n const size = spriteScale * 1.5;\n\n const direction = cardinalDirection(entity.direction ?? 0);\n const angle = direction * 22.5;\n const radians = (angle * Math.PI) / 180;\n const forward: [number, number] = [Math.sin(radians), -Math.cos(radians)];\n const halfSpan = Math.max(\n Math.abs(def.selectionBox[0][0]),\n Math.abs(def.selectionBox[0][1]),\n Math.abs(def.selectionBox[1][0]),\n Math.abs(def.selectionBox[1][1]),\n );\n const frameMeta = db.frames[frame];\n const visibleArrowHeight = frameMeta ? size * (frameMeta.h / Math.max(1, frameMeta.sh)) : 0;\n // Factorio tucks each marker inward by its visible height rather than\n // centering it directly on the selection-box edge.\n const flowOffset = Math.max(0, halfSpan - visibleArrowHeight);\n\n return ([-1, 1] as const).map((side, index) => ({\n kind: \"icon\" as const,\n layer: RENDER_LAYERS[\"entity-info-icon-above\"],\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: 110 + index,\n frame,\n x: entity.position.x + forward[0] * flowOffset * side,\n y: entity.position.y + forward[1] * flowOffset * side,\n size,\n rotation: angle,\n }));\n}\n\n/** A filter-enabled inserter with no selected filter shows Factorio's prohibition marker. */\nfunction emptyInserterFilterCommand(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n db: RenderDb,\n): IconCmd | undefined {\n if (def.kind !== \"inserter\" || entity.use_filters !== true) return undefined;\n if (filterSignals(entity.filters).length > 0) return undefined;\n const frame = db.icons[\"virtual-signal/signal-no-entry\"];\n if (frame === undefined) return undefined;\n const spec = iconDrawSpec(def);\n return {\n kind: \"icon\",\n layer: RENDER_LAYERS[\"entity-info-icon-above\"],\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: 112,\n frame,\n x: entity.position.x + spec.shift[0],\n y: entity.position.y + spec.shift[1],\n size: spec.scale,\n silhouette: true,\n };\n}\n\n/** Build deterministic alt-mode (entity-info) commands for one blueprint entity. */\nexport function planAltModeCommands(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n db: RenderDb,\n opts?: { insertCommands?: IconCmd[] },\n): IconCmd[] {\n const spec = iconDrawSpec(def);\n const primary = resolveAltSignals(db, entitySignals(entity, def));\n const primaryScale = primary.length > 1 ? spec.scaleForMany : spec.scale;\n const primaryOffsets = iconLayout(primary.length, primaryScale);\n const darkBackingFrame = db.icons[\"utility/entity-info-dark-background\"];\n const layer = RENDER_LAYERS[spec.renderLayer];\n const primaryCommands: IconCmd[] = primary.map(({ frame }, index) => ({\n kind: \"icon\",\n layer,\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: index,\n frame,\n x: entity.position.x + spec.shift[0] + (primaryOffsets[index]?.[0] ?? 0),\n y: entity.position.y + spec.shift[1] + (primaryOffsets[index]?.[1] ?? 0),\n size: primaryScale,\n ...(darkBackingFrame !== undefined ? { backingFrame: darkBackingFrame } : { backing: true }),\n }));\n\n const insertCommands = opts?.insertCommands ?? [];\n const insertPlans =\n insertCommands.length > 0\n ? resolveAltSignals(db, insertPlanSignals(entity.items)).slice(0, insertCommands.length)\n : [];\n\n const commands: IconCmd[] = [\n ...primaryCommands,\n ...qualityBadgeCommands(primary, primaryCommands, entity.entity_number, db, 50),\n ...(insertCommands.length > 0\n ? qualityBadgeCommands(insertPlans, insertCommands, entity.entity_number, db, 60)\n : []),\n ];\n\n if (\n entity.filter_mode === \"blacklist\" &&\n commands.length > 0 &&\n !splitterLaneFilter(entity, def)\n ) {\n const frame = db.icons[\"utility/filter-blacklist\"];\n if (frame !== undefined) {\n commands.push({\n kind: \"icon\",\n layer: RENDER_LAYERS[\"entity-info-icon-above\"],\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: 80,\n frame,\n x: commands[0]!.x + commands[0]!.size * 0.28,\n y: commands[0]!.y + commands[0]!.size * 0.28,\n size: commands[0]!.size * 0.45,\n });\n }\n }\n\n const quality = entity.quality;\n if (quality && quality !== \"normal\") {\n const frame = db.icons[`quality/${quality}`] ?? db.icons[\"utility/missing-icon\"];\n if (frame !== undefined) {\n const size = ENTITY_QUALITY_BADGE_TILES * qualityIndicatorScale(def);\n const [x1] = def.selectionBox[0];\n const [, y2] = def.selectionBox[1];\n commands.push({\n kind: \"icon\",\n layer: RENDER_LAYERS[\"entity-info-icon-above\"],\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: 90,\n frame,\n x: entity.position.x + x1 + size / 2,\n y: entity.position.y + y2 - size / 2,\n size,\n });\n }\n }\n\n commands.push(...splitterPriorityCommands(entity, def, db, 100));\n commands.push(...combinatorFlowCommands(entity, def, db));\n const emptyFilter = emptyInserterFilterCommand(entity, def, db);\n if (emptyFilter) commands.push(emptyFilter);\n return commands;\n}\n","import { signalIconKeys } from \"./alt-mode.js\";\nimport type { Icon } from \"./types/blueprint.js\";\n\n/** Display size of the composited blueprint tile (matches Factorio GUI slot). */\nexport const BLUEPRINT_ICON_TILE_SIZE = 64;\n\nexport type BlueprintIconVariant = \"blueprint\" | \"book\";\n\n/** Signal sizes on a 64px tile, matching Factorio inventory thumbnails. */\nconst VARIANT_LAYOUT: Record<\n BlueprintIconVariant,\n { singleSignalPx: number; multiSignalPx: number; gapPx: number }\n> = {\n blueprint: { singleSignalPx: 48, multiSignalPx: 28, gapPx: 4 },\n book: { singleSignalPx: 24, multiSignalPx: 18, gapPx: 3 },\n};\n\n/** Vertical offset on a 64px tile by filled-icon count (negative moves up). */\nconst SIGNAL_Y_OFFSET_PX: Record<BlueprintIconVariant, Partial<Record<1 | 2 | 3 | 4, number>>> = {\n blueprint: {},\n book: { 1: -4, 2: -5, 3: -6, 4: -6 },\n};\n\nfunction packedCentersForVariant(\n variant: BlueprintIconVariant,\n): Record<number, ReadonlyArray<{ x: number; y: number }>> {\n const { multiSignalPx, gapPx } = VARIANT_LAYOUT[variant];\n const gridCenter = (BLUEPRINT_ICON_TILE_SIZE - multiSignalPx * 2 - gapPx) / 2 + multiSignalPx / 2;\n const gridFar = BLUEPRINT_ICON_TILE_SIZE - gridCenter;\n const near = gridCenter / BLUEPRINT_ICON_TILE_SIZE;\n const far = gridFar / BLUEPRINT_ICON_TILE_SIZE;\n\n return {\n 1: [{ x: 0.5, y: 0.5 }],\n 2: [\n { x: near, y: 0.5 },\n { x: far, y: 0.5 },\n ],\n 3: [\n { x: near, y: near },\n { x: far, y: near },\n { x: near, y: far },\n ],\n 4: [\n { x: near, y: near },\n { x: far, y: near },\n { x: near, y: far },\n { x: far, y: far },\n ],\n };\n}\n\nconst PACKED_CENTERS: Record<\n BlueprintIconVariant,\n Record<number, ReadonlyArray<{ x: number; y: number }>>\n> = {\n blueprint: packedCentersForVariant(\"blueprint\"),\n book: packedCentersForVariant(\"book\"),\n};\n\nexport function filledBlueprintIcons(icons: Icon[] | undefined): Icon[] {\n if (!icons) return [];\n return icons\n .filter((icon) => icon.index >= 1 && icon.index <= 4 && icon.signal?.name)\n .slice()\n .sort((a, b) => a.index - b.index);\n}\n\n/** Signal size in px for a given tile size and filled-icon count. */\nexport function blueprintIconSignalSizePx(\n tileSize: number,\n count: number,\n variant: BlueprintIconVariant = \"blueprint\",\n): number {\n const n = Math.min(4, Math.max(1, count));\n const { singleSignalPx, multiSignalPx } = VARIANT_LAYOUT[variant];\n const base = n === 1 ? singleSignalPx : multiSignalPx;\n return (base / BLUEPRINT_ICON_TILE_SIZE) * tileSize;\n}\n\n/** Signal scale as a fraction of the tile. */\nexport function blueprintIconSignalScale(\n count: number,\n variant: BlueprintIconVariant = \"blueprint\",\n): number {\n return (\n blueprintIconSignalSizePx(BLUEPRINT_ICON_TILE_SIZE, count, variant) / BLUEPRINT_ICON_TILE_SIZE\n );\n}\n\n/** Vertical offset in px for signal overlays (negative moves up). */\nexport function blueprintIconSignalYOffsetPx(\n tileSize: number,\n count: number,\n variant: BlueprintIconVariant = \"blueprint\",\n): number {\n const n = Math.min(4, Math.max(1, count)) as 1 | 2 | 3 | 4;\n const base = SIGNAL_Y_OFFSET_PX[variant][n] ?? 0;\n return (base / BLUEPRINT_ICON_TILE_SIZE) * tileSize;\n}\n\n/** Normalized center for a signal on the blueprint tile (rank is 0-based in sorted order). */\nexport function blueprintIconSignalCenter(\n count: number,\n rank: number,\n variant: BlueprintIconVariant = \"blueprint\",\n): { x: number; y: number } {\n const packed = PACKED_CENTERS[variant][Math.min(4, Math.max(1, count))];\n return packed?.[rank] ?? { x: 0.5, y: 0.5 };\n}\n\nfunction resolveVariant(\n variant: BlueprintIconVariant | undefined,\n backgroundKey: string,\n): BlueprintIconVariant {\n if (variant) return variant;\n return backgroundKey === \"item/blueprint-book\" ? \"book\" : \"blueprint\";\n}\n\nexport interface BlueprintIconSignalPlan {\n icon: Icon;\n iconKeys: string[];\n left: number;\n top: number;\n size: number;\n}\n\nexport interface BlueprintIconPlan {\n variant: BlueprintIconVariant;\n backgroundKey: string;\n tileSize: number;\n signals: BlueprintIconSignalPlan[];\n}\n\nexport interface PlanBlueprintIconsOptions {\n variant?: BlueprintIconVariant;\n /** Render-db key for the paper background. */\n backgroundKey?: string;\n /** Outer tile size in px. */\n tileSize?: number;\n}\n\n/**\n * Plans blueprint preview icon layout for inventory thumbnails — background paper\n * plus up to four signal overlays, matching Factorio GUI slot sizes and packing.\n */\nexport function planBlueprintIcons(\n icons: Icon[] | undefined,\n opts: PlanBlueprintIconsOptions = {},\n): BlueprintIconPlan {\n const backgroundKey = opts.backgroundKey ?? \"item/blueprint\";\n const tileSize = opts.tileSize ?? BLUEPRINT_ICON_TILE_SIZE;\n const variant = resolveVariant(opts.variant, backgroundKey);\n const filled = filledBlueprintIcons(icons);\n const count = filled.length;\n const signalSize = blueprintIconSignalSizePx(tileSize, count, variant);\n const signalYOffset = blueprintIconSignalYOffsetPx(tileSize, count, variant);\n\n const signals: BlueprintIconSignalPlan[] = filled.map((icon, rank) => {\n const { signal } = icon;\n const { x, y } = blueprintIconSignalCenter(count, rank, variant);\n return {\n icon,\n iconKeys: signalIconKeys(signal),\n left: x * tileSize - signalSize / 2,\n top: y * tileSize - signalSize / 2 + signalYOffset,\n size: signalSize,\n };\n });\n\n return { variant, backgroundKey, tileSize, signals };\n}\n","import { filledBlueprintIcons } from \"./blueprint-icons.js\";\nimport type { Color, Icon } from \"./types/blueprint.js\";\n\n/** Factorio default entity filter slot count on the deconstruction planner. */\nexport const DECONSTRUCTION_ENTITY_FILTER_SLOT_COUNT = 30;\n/** Factorio default tile filter slot count on the deconstruction planner. */\nexport const DECONSTRUCTION_TILE_FILTER_SLOT_COUNT = 30;\n\n/** `defines.deconstruction_item.entity_filter_mode` / `tile_filter_mode`. */\nexport type DeconstructionFilterMode = \"whitelist\" | \"blacklist\";\n\n/** `defines.deconstruction_item.tile_selection_mode`. */\nexport type DeconstructionTileSelectionMode = \"normal\" | \"always\" | \"never\" | \"only\";\n\nexport interface DeconstructionEntityFilter {\n index: number;\n name?: string;\n type?: string;\n quality?: string;\n comparator?: string;\n [key: string]: unknown;\n}\n\nexport interface DeconstructionTileFilter {\n index: number;\n name?: string;\n [key: string]: unknown;\n}\n\nexport interface DeconstructionPlannerSettings {\n entity_filters?: DeconstructionEntityFilter[];\n tile_filters?: DeconstructionTileFilter[];\n /** 0 whitelist, 1 blacklist (Factorio enum). */\n entity_filter_mode?: number;\n /** 0 whitelist, 1 blacklist (Factorio enum). */\n tile_filter_mode?: number;\n /** 0 normal, 1 always, 2 never, 3 only (Factorio enum). */\n tile_selection_mode?: number;\n trees_and_rocks_only?: boolean;\n [key: string]: unknown;\n}\n\nexport interface DeconstructionPlanner {\n item?: string;\n label?: string;\n label_color?: Color;\n description?: string;\n icons?: Icon[];\n version?: number;\n settings?: DeconstructionPlannerSettings;\n [key: string]: unknown;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseIndexedFilter(\n value: unknown,\n): { index: number; rest: Record<string, unknown> } | undefined {\n if (!isPlainObject(value)) return undefined;\n const index = value.index;\n if (typeof index !== \"number\" || !Number.isInteger(index) || index < 0) return undefined;\n return { index, rest: value };\n}\n\nfunction parseEntityFilter(value: unknown): DeconstructionEntityFilter | undefined {\n const parsed = parseIndexedFilter(value);\n if (!parsed) return undefined;\n return { ...parsed.rest, index: parsed.index };\n}\n\nfunction parseTileFilter(value: unknown): DeconstructionTileFilter | undefined {\n const parsed = parseIndexedFilter(value);\n if (!parsed) return undefined;\n return { ...parsed.rest, index: parsed.index };\n}\n\nfunction readFilterMode(value: unknown): DeconstructionFilterMode {\n return value === 1 ? \"blacklist\" : \"whitelist\";\n}\n\nfunction readTileSelectionMode(value: unknown): DeconstructionTileSelectionMode {\n switch (value) {\n case 1:\n return \"always\";\n case 2:\n return \"never\";\n case 3:\n return \"only\";\n default:\n return \"normal\";\n }\n}\n\nfunction settingsOf(\n planner: Record<string, unknown> | DeconstructionPlanner,\n): DeconstructionPlannerSettings | undefined {\n const settings = planner.settings;\n return isPlainObject(settings) ? (settings as DeconstructionPlannerSettings) : undefined;\n}\n\n/**\n * Expand `settings.entity_filters` into a fixed-length slot array keyed by `index`.\n * Out-of-range indices are ignored. Duplicate indices keep the last filter.\n */\nexport function deconstructionEntityFilters(\n planner: Record<string, unknown> | DeconstructionPlanner,\n): (DeconstructionEntityFilter | undefined)[] {\n const slots: (DeconstructionEntityFilter | undefined)[] = Array.from(\n { length: DECONSTRUCTION_ENTITY_FILTER_SLOT_COUNT },\n () => undefined,\n );\n const settings = settingsOf(planner);\n const filters = settings?.entity_filters;\n if (!Array.isArray(filters)) return slots;\n for (const entry of filters) {\n const filter = parseEntityFilter(entry);\n if (!filter || filter.index >= DECONSTRUCTION_ENTITY_FILTER_SLOT_COUNT) continue;\n slots[filter.index] = filter;\n }\n return slots;\n}\n\n/**\n * Expand `settings.tile_filters` into a fixed-length slot array keyed by `index`.\n * Out-of-range indices are ignored. Duplicate indices keep the last filter.\n */\nexport function deconstructionTileFilters(\n planner: Record<string, unknown> | DeconstructionPlanner,\n): (DeconstructionTileFilter | undefined)[] {\n const slots: (DeconstructionTileFilter | undefined)[] = Array.from(\n { length: DECONSTRUCTION_TILE_FILTER_SLOT_COUNT },\n () => undefined,\n );\n const settings = settingsOf(planner);\n const filters = settings?.tile_filters;\n if (!Array.isArray(filters)) return slots;\n for (const entry of filters) {\n const filter = parseTileFilter(entry);\n if (!filter || filter.index >= DECONSTRUCTION_TILE_FILTER_SLOT_COUNT) continue;\n slots[filter.index] = filter;\n }\n return slots;\n}\n\nexport function deconstructionEntityFilterMode(\n planner: Record<string, unknown> | DeconstructionPlanner,\n): DeconstructionFilterMode {\n return readFilterMode(settingsOf(planner)?.entity_filter_mode);\n}\n\nexport function deconstructionTileFilterMode(\n planner: Record<string, unknown> | DeconstructionPlanner,\n): DeconstructionFilterMode {\n return readFilterMode(settingsOf(planner)?.tile_filter_mode);\n}\n\nexport function deconstructionTileSelectionMode(\n planner: Record<string, unknown> | DeconstructionPlanner,\n): DeconstructionTileSelectionMode {\n return readTileSelectionMode(settingsOf(planner)?.tile_selection_mode);\n}\n\nexport function deconstructionTreesAndRocksOnly(\n planner: Record<string, unknown> | DeconstructionPlanner,\n): boolean {\n return settingsOf(planner)?.trees_and_rocks_only === true;\n}\n\nexport function formatDeconstructionFilterMode(mode: DeconstructionFilterMode): string {\n return mode === \"blacklist\" ? \"Blacklist\" : \"Whitelist\";\n}\n\nexport function formatDeconstructionTileSelectionMode(\n mode: DeconstructionTileSelectionMode,\n): string {\n switch (mode) {\n case \"always\":\n return \"Always\";\n case \"never\":\n return \"Never\";\n case \"only\":\n return \"Only\";\n default:\n return \"Normal\";\n }\n}\n\n/**\n * Icons for the deconstruction-planner inventory thumbnail.\n * Prefers an explicit `icons` field; `trees_and_rocks_only` uses tree-01;\n * otherwise uses the first filled entity filters then tile filters (max 4).\n */\nexport function deconstructionPlannerIcons(\n planner: Record<string, unknown> | DeconstructionPlanner,\n): Icon[] {\n const typed = planner as DeconstructionPlanner;\n const explicit = filledBlueprintIcons(typed.icons);\n if (explicit.length > 0) return explicit;\n\n if (deconstructionTreesAndRocksOnly(planner)) {\n return [{ index: 1, signal: { name: \"tree-01\", type: \"entity\" } }];\n }\n\n const icons: Icon[] = [];\n for (const filter of deconstructionEntityFilters(planner)) {\n if (!filter?.name) continue;\n const quality = filter.quality;\n icons.push({\n index: icons.length + 1,\n signal: {\n name: filter.name,\n type: filter.type ?? \"entity\",\n ...(typeof quality === \"string\" && quality !== \"normal\" ? { quality } : {}),\n },\n });\n if (icons.length >= 4) return icons;\n }\n for (const filter of deconstructionTileFilters(planner)) {\n if (!filter?.name) continue;\n icons.push({\n index: icons.length + 1,\n signal: { name: filter.name, type: \"tile\" },\n });\n if (icons.length >= 4) break;\n }\n return icons;\n}\n\n/** Read a typed deconstruction planner view from an opaque document payload. */\nexport function asDeconstructionPlanner(\n planner: Record<string, unknown> | DeconstructionPlanner,\n): DeconstructionPlanner {\n return planner as DeconstructionPlanner;\n}\n","import { filledBlueprintIcons } from \"./blueprint-icons.js\";\nimport type { Color, Icon } from \"./types/blueprint.js\";\n\n/** Factorio upgrade planner filter window has 24 entity slot pairs. */\nexport const UPGRADE_PLANNER_SLOT_COUNT = 24;\n\n/** Source side of an upgrade mapper (`UpgradeMapperSource`). */\nexport interface UpgradeMapperSource {\n type?: string;\n name?: string;\n quality?: string;\n comparator?: string;\n [key: string]: unknown;\n}\n\n/** Destination side of an upgrade mapper (`UpgradeMapperDestination`). */\nexport interface UpgradeMapperDestination {\n type?: string;\n name?: string;\n quality?: string;\n module_limit?: number;\n module_slots?: unknown[];\n [key: string]: unknown;\n}\n\nexport interface UpgradeMapper {\n index: number;\n from?: UpgradeMapperSource;\n to?: UpgradeMapperDestination;\n [key: string]: unknown;\n}\n\nexport interface UpgradePlanner {\n item?: string;\n label?: string;\n label_color?: Color;\n description?: string;\n icons?: Icon[];\n version?: number;\n settings?: {\n mappers?: UpgradeMapper[];\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseMapperSide(\n value: unknown,\n): UpgradeMapperSource | UpgradeMapperDestination | undefined {\n if (!isPlainObject(value)) return undefined;\n return value as UpgradeMapperSource;\n}\n\nfunction parseMapper(value: unknown): UpgradeMapper | undefined {\n if (!isPlainObject(value)) return undefined;\n const index = value.index;\n if (typeof index !== \"number\" || !Number.isInteger(index) || index < 0) return undefined;\n return {\n ...value,\n index,\n from: parseMapperSide(value.from),\n to: parseMapperSide(value.to),\n };\n}\n\n/**\n * Expand `settings.mappers` into a fixed-length slot array keyed by `mapper.index`.\n * Out-of-range indices are ignored. Duplicate indices keep the last mapper.\n */\nexport function upgradePlannerMappers(\n planner: Record<string, unknown> | UpgradePlanner,\n): (UpgradeMapper | undefined)[] {\n const slots: (UpgradeMapper | undefined)[] = Array.from(\n { length: UPGRADE_PLANNER_SLOT_COUNT },\n () => undefined,\n );\n const settings = planner.settings;\n if (!isPlainObject(settings)) return slots;\n const mappers = settings.mappers;\n if (!Array.isArray(mappers)) return slots;\n for (const entry of mappers) {\n const mapper = parseMapper(entry);\n if (!mapper || mapper.index >= UPGRADE_PLANNER_SLOT_COUNT) continue;\n slots[mapper.index] = mapper;\n }\n return slots;\n}\n\n/**\n * Icons for the upgrade-planner inventory thumbnail.\n * Prefers an explicit `icons` field; otherwise uses the `to` side of the first\n * four filled mapper pairs (Factorio GUI behavior).\n */\nexport function upgradePlannerIcons(planner: Record<string, unknown> | UpgradePlanner): Icon[] {\n const typed = planner as UpgradePlanner;\n const explicit = filledBlueprintIcons(typed.icons);\n if (explicit.length > 0) return explicit;\n\n const icons: Icon[] = [];\n for (const mapper of upgradePlannerMappers(planner)) {\n if (!mapper?.to?.name) continue;\n const quality = mapper.to.quality;\n icons.push({\n index: icons.length + 1,\n signal: {\n name: mapper.to.name,\n type: mapper.to.type ?? \"entity\",\n ...(typeof quality === \"string\" && quality !== \"normal\" ? { quality } : {}),\n },\n });\n if (icons.length >= 4) break;\n }\n return icons;\n}\n\n/** Read a typed upgrade planner view from an opaque document payload. */\nexport function asUpgradePlanner(\n planner: Record<string, unknown> | UpgradePlanner,\n): UpgradePlanner {\n return planner as UpgradePlanner;\n}\n","import type { RenderDb } from \"./types/render-db.js\";\n\n/** Resolve a render-db icon key to a frame id, including tile placing-item fallback. */\nexport function resolveIconFrameId(db: RenderDb, iconKey: string): number | undefined {\n const direct = db.icons[iconKey];\n if (direct !== undefined) return direct;\n\n if (!iconKey.startsWith(\"item/\")) return undefined;\n\n const tileName = iconKey.slice(\"item/\".length);\n const placingItem = db.tiles[tileName]?.item;\n if (!placingItem) return undefined;\n\n return db.icons[`item/${placingItem}`];\n}\n","import { entityInfoSilhouettePadPx } from \"../icon-silhouette.js\";\nimport { TRAIN_CHAIN_JOINT_RADIUS } from \"../train-chains.js\";\nimport type { DrawCmd, DrawList, SpriteCmd } from \"../types/draw-list.js\";\nimport type { FrameMeta, SpriteVariant } from \"../types/render-db.js\";\n\nexport function spriteDest(\n posX: number,\n posY: number,\n frame: FrameMeta,\n variant: SpriteVariant,\n extraShift?: [number, number],\n): { x: number; y: number; w: number; h: number } {\n const w = (frame.sw * variant.scale) / 32;\n const h = (frame.sh * variant.scale * (variant.scaleY ?? 1)) / 32;\n const sx = extraShift?.[0] ?? 0;\n const sy = extraShift?.[1] ?? 0;\n const cx = posX + variant.shift[0] + sx;\n const cy = posY + variant.shift[1] + sy;\n return { x: cx - w / 2, y: cy - h / 2, w, h };\n}\n\n/**\n * Open-side half of a UG/loader belt underlay (Factorio/FBE: only half the belt\n * shows under the hood). `openDir` is the direction toward the hood opening.\n */\nexport function undergroundBeltUnderlayClip(\n dest: { x: number; y: number; w: number; h: number },\n openDir: 0 | 4 | 8 | 12,\n): { x: number; y: number; w: number; h: number } {\n switch (openDir) {\n case 4: // east half\n return { x: dest.x + dest.w / 2, y: dest.y, w: dest.w / 2, h: dest.h };\n case 12: // west half\n return { x: dest.x, y: dest.y, w: dest.w / 2, h: dest.h };\n case 8: // south half\n return { x: dest.x, y: dest.y + dest.h / 2, w: dest.w, h: dest.h / 2 };\n case 0: // north half\n return { x: dest.x, y: dest.y, w: dest.w, h: dest.h / 2 };\n }\n}\n\nexport function expandBounds(\n bounds: DrawList[\"bounds\"] | null,\n x: number,\n y: number,\n w: number,\n h: number,\n): DrawList[\"bounds\"] {\n const minX = x;\n const minY = y;\n const maxX = x + w;\n const maxY = y + h;\n if (!bounds) {\n return { minX, minY, maxX, maxY };\n }\n return {\n minX: Math.min(bounds.minX, minX),\n minY: Math.min(bounds.minY, minY),\n maxX: Math.max(bounds.maxX, maxX),\n maxY: Math.max(bounds.maxY, maxY),\n };\n}\n\nexport function spriteVisibleBounds(\n cmd: SpriteCmd,\n frame: FrameMeta,\n): {\n x: number;\n y: number;\n w: number;\n h: number;\n} {\n if (cmd.src) {\n return { x: cmd.x, y: cmd.y, w: cmd.w, h: cmd.h };\n }\n const scaleX = frame.sw === 0 ? 0 : cmd.w / frame.sw;\n const scaleY = frame.sh === 0 ? 0 : cmd.h / frame.sh;\n const cx = cmd.x + cmd.w / 2;\n const cy = cmd.y + cmd.h / 2;\n let left = cmd.x + frame.ox * scaleX;\n let top = cmd.y + frame.oy * scaleY;\n let right = left + frame.w * scaleX;\n let bottom = top + frame.h * scaleY;\n\n if (cmd.flipX) [left, right] = [2 * cx - right, 2 * cx - left];\n if (cmd.flipY) [top, bottom] = [2 * cy - bottom, 2 * cy - top];\n\n const rotation = cmd.rotation ?? 0;\n if (rotation % 360 !== 0) {\n const radians = (rotation * Math.PI) / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n const corners = [\n [left, top],\n [right, top],\n [right, bottom],\n [left, bottom],\n ] as const;\n const rotated = corners.map(([x, y]) => {\n const dx = x - cx;\n const dy = y - cy;\n return [cx + dx * cos - dy * sin, cy + dx * sin + dy * cos] as const;\n });\n left = Math.min(...rotated.map(([x]) => x));\n top = Math.min(...rotated.map(([, y]) => y));\n right = Math.max(...rotated.map(([x]) => x));\n bottom = Math.max(...rotated.map(([, y]) => y));\n }\n\n if (cmd.clip) {\n left = Math.max(left, cmd.clip.x);\n top = Math.max(top, cmd.clip.y);\n right = Math.max(left, Math.min(right, cmd.clip.x + cmd.clip.w));\n bottom = Math.max(top, Math.min(bottom, cmd.clip.y + cmd.clip.h));\n }\n\n return { x: left, y: top, w: right - left, h: bottom - top };\n}\n\nexport function includeCmdBounds(\n bounds: DrawList[\"bounds\"] | null,\n cmd: DrawCmd,\n frames?: FrameMeta[],\n frameOverride?: FrameMeta,\n): DrawList[\"bounds\"] {\n switch (cmd.kind) {\n case \"sprite\": {\n const frame = frameOverride ?? frames?.[cmd.frame];\n const visible = frame ? spriteVisibleBounds(cmd, frame) : cmd;\n return expandBounds(bounds, visible.x, visible.y, visible.w, visible.h);\n }\n case \"rect\": {\n return expandBounds(bounds, cmd.x, cmd.y, cmd.w, cmd.h);\n }\n case \"icon\": {\n const backing = cmd.backingFrame == null ? undefined : frames?.[cmd.backingFrame];\n const isRequestPin = cmd.backingStyle === \"request-pin\";\n // Entity-info: 53 px no-scale backing around a 32 px scale-1 icon, plus\n // silhouette pad. Request-pin: cmd.size is opaque chrome width.\n const backingBasePx = isRequestPin ? Math.max(1, (backing?.w ?? 48) * (44 / 48)) : 32;\n const backingScale = cmd.size / backingBasePx;\n const silhouettePad =\n !isRequestPin &&\n (cmd.backingFrame != null || cmd.backing === true || cmd.silhouette === true)\n ? (entityInfoSilhouettePadPx() / 32) * cmd.size\n : 0;\n const width = Math.max(cmd.size + 2 * silhouettePad, (backing?.sw ?? 0) * backingScale);\n const height = Math.max(cmd.size + 2 * silhouettePad, (backing?.sh ?? 0) * backingScale);\n return expandBounds(bounds, cmd.x - width / 2, cmd.y - height / 2, width, height);\n }\n case \"wire\": {\n const minX = Math.min(cmd.x1, cmd.x2);\n const minY = Math.min(cmd.y1, cmd.y2);\n const maxX = Math.max(cmd.x1, cmd.x2);\n const maxY = Math.max(cmd.y1, cmd.y2);\n const mx = (cmd.x1 + cmd.x2) / 2;\n const my = (cmd.y1 + cmd.y2) / 2;\n const dist = Math.hypot(cmd.x2 - cmd.x1, cmd.y2 - cmd.y1);\n const sagY = my + 0.15 * dist;\n return expandBounds(\n expandBounds(bounds, minX, minY, maxX - minX, maxY - minY),\n mx,\n sagY,\n 0,\n 0,\n );\n }\n case \"train-chain\": {\n let b = bounds;\n for (const s of cmd.segments) {\n const minX = Math.min(s.x1, s.x2);\n const minY = Math.min(s.y1, s.y2);\n const maxX = Math.max(s.x1, s.x2);\n const maxY = Math.max(s.y1, s.y2);\n b = expandBounds(b, minX, minY, maxX - minX, maxY - minY);\n }\n for (const j of cmd.joints) {\n b = expandBounds(\n b,\n j.x - TRAIN_CHAIN_JOINT_RADIUS,\n j.y - TRAIN_CHAIN_JOINT_RADIUS,\n TRAIN_CHAIN_JOINT_RADIUS * 2,\n TRAIN_CHAIN_JOINT_RADIUS * 2,\n );\n }\n return b ?? { minX: 0, minY: 0, maxX: 0, maxY: 0 };\n }\n case \"snap-grid\": {\n return expandBounds(bounds, cmd.x, cmd.y, cmd.w, cmd.h);\n }\n case \"text\": {\n // Approximate glyph box: width unknown without measureText; use size × chars.\n const width = Math.max(cmd.size, cmd.text.length * cmd.size * 0.55);\n const height = cmd.size;\n const align = cmd.align ?? \"left\";\n const baseline = cmd.baseline ?? \"top\";\n const x = align === \"center\" ? cmd.x - width / 2 : align === \"right\" ? cmd.x - width : cmd.x;\n const y =\n baseline === \"middle\"\n ? cmd.y - height / 2\n : baseline === \"alphabetic\"\n ? cmd.y - height\n : cmd.y;\n return expandBounds(bounds, x, y, width, height);\n }\n }\n}\n","import { altSignalFrame } from \"../alt-mode-signals.js\";\nimport {\n deconstructionEntityFilterMode,\n deconstructionEntityFilters,\n deconstructionTileFilterMode,\n deconstructionTileFilters,\n deconstructionTileSelectionMode,\n deconstructionTreesAndRocksOnly,\n formatDeconstructionFilterMode,\n formatDeconstructionTileSelectionMode,\n type DeconstructionEntityFilter,\n type DeconstructionPlanner,\n type DeconstructionTileFilter,\n} from \"../deconstruction-planner.js\";\nimport { resolveIconFrameId } from \"../icon-resolve.js\";\nimport type { SignalId } from \"../types/blueprint.js\";\nimport {\n compareDrawCmd,\n RENDER_LAYERS,\n type DrawList,\n type IconCmd,\n type TextCmd,\n} from \"../types/draw-list.js\";\nimport type { RenderDb } from \"../types/render-db.js\";\nimport { expandBounds, includeCmdBounds } from \"./bounds.js\";\n\n/** Columns in the Factorio-style deconstruction planner filter grids. */\nexport const DECONSTRUCTION_PLANNER_COLUMNS = 12;\n\n/** Icon used when `trees_and_rocks_only` is set (Factorio deconstruction alternative). */\nexport const TREES_AND_ROCKS_ICON_KEY = \"entity/tree-01\";\n\nconst OUTER_PAD = 1;\nconst ICON_GAP = 0;\nconst ICON_SIZE = 1;\n/** One full tile row for a section header so icon grids stay on integer tiles. */\nconst HEADER_ROWS = 1;\nconst SECTION_GAP = 1;\nconst TEXT_SIZE = 0.35;\nconst TEXT_COLOR: [number, number, number, number] = [1, 1, 1, 0.92];\nconst HEADER_ENTITY = 0;\n\nfunction tileCenter(tileX: number, tileY: number): { x: number; y: number } {\n return { x: tileX + 0.5, y: tileY + 0.5 };\n}\n\nfunction occupiedRows(slotCount: number, lastIndex: number): number {\n if (lastIndex < 0) return 0;\n return Math.floor(lastIndex / slotCount) + 1;\n}\n\nfunction lastOccupiedIndex(slots: ({ name?: string } | undefined)[]): number {\n let maxIndex = -1;\n for (let index = 0; index < slots.length; index++) {\n if (slots[index]?.name) maxIndex = index;\n }\n return maxIndex;\n}\n\nfunction gridWidth(): number {\n return (\n OUTER_PAD +\n DECONSTRUCTION_PLANNER_COLUMNS * ICON_SIZE +\n (DECONSTRUCTION_PLANNER_COLUMNS - 1) * ICON_GAP +\n OUTER_PAD\n );\n}\n\nfunction sectionBodyHeight(rows: number): number {\n if (rows === 0) return 0;\n return rows * ICON_SIZE + (rows - 1) * ICON_GAP;\n}\n\nfunction textCommand(text: string, x: number, y: number, entity: number, sub: number): TextCmd {\n return {\n kind: \"text\",\n layer: RENDER_LAYERS.icons,\n sortY: y,\n sortX: x,\n entity,\n sub,\n text,\n x,\n y,\n size: TEXT_SIZE,\n color: TEXT_COLOR,\n align: \"left\",\n baseline: \"middle\",\n };\n}\n\nfunction entityIconCommand(\n db: RenderDb,\n filter: DeconstructionEntityFilter,\n x: number,\n y: number,\n entity: number,\n sub: number,\n): IconCmd | undefined {\n const signal: SignalId = {\n name: filter.name!,\n type: filter.type ?? \"entity\",\n ...(typeof filter.quality === \"string\" && filter.quality !== \"normal\"\n ? { quality: filter.quality }\n : {}),\n };\n const frame = altSignalFrame(db, signal) ?? db.icons[\"utility/missing-icon\"];\n if (frame === undefined) return undefined;\n return {\n kind: \"icon\",\n layer: RENDER_LAYERS.icons,\n sortY: y,\n sortX: x,\n entity,\n sub,\n frame,\n x,\n y,\n size: ICON_SIZE,\n };\n}\n\nfunction tileIconCommand(\n db: RenderDb,\n filter: DeconstructionTileFilter,\n x: number,\n y: number,\n entity: number,\n sub: number,\n): IconCmd | undefined {\n const frame = resolveIconFrameId(db, `tile/${filter.name}`) ?? db.icons[\"utility/missing-icon\"];\n if (frame === undefined) return undefined;\n return {\n kind: \"icon\",\n layer: RENDER_LAYERS.icons,\n sortY: y,\n sortX: x,\n entity,\n sub,\n frame,\n x,\n y,\n size: ICON_SIZE,\n };\n}\n\nfunction treeIconCommand(db: RenderDb, x: number, y: number): IconCmd | undefined {\n const frame =\n db.icons[TREES_AND_ROCKS_ICON_KEY] ??\n altSignalFrame(db, { name: \"tree-01\", type: \"entity\" }) ??\n db.icons[\"utility/missing-icon\"];\n if (frame === undefined) return undefined;\n return {\n kind: \"icon\",\n layer: RENDER_LAYERS.icons,\n sortY: y,\n sortX: x,\n entity: 1,\n sub: 0,\n frame,\n x,\n y,\n size: ICON_SIZE,\n };\n}\n\nfunction pushIconGrid(\n commands: (IconCmd | TextCmd)[],\n bounds: DrawList[\"bounds\"],\n db: RenderDb,\n slots: (DeconstructionEntityFilter | DeconstructionTileFilter | undefined)[],\n rows: number,\n originY: number,\n kind: \"entity\" | \"tile\",\n): DrawList[\"bounds\"] {\n let nextBounds = bounds;\n const colStride = ICON_SIZE + ICON_GAP;\n const rowStride = ICON_SIZE + ICON_GAP;\n const slotLimit = Math.min(slots.length, rows * DECONSTRUCTION_PLANNER_COLUMNS);\n\n for (let index = 0; index < slotLimit; index++) {\n const filter = slots[index];\n if (!filter?.name) continue;\n const col = index % DECONSTRUCTION_PLANNER_COLUMNS;\n const row = Math.floor(index / DECONSTRUCTION_PLANNER_COLUMNS);\n // originY is an integer tile row; centers land on *.5.\n const pos = tileCenter(OUTER_PAD + col * colStride, originY + row * rowStride);\n const entity = (kind === \"entity\" ? 1000 : 2000) + index + 1;\n const cmd =\n kind === \"entity\"\n ? entityIconCommand(db, filter as DeconstructionEntityFilter, pos.x, pos.y, entity, 0)\n : tileIconCommand(db, filter as DeconstructionTileFilter, pos.x, pos.y, entity, 0);\n if (!cmd) continue;\n commands.push(cmd);\n nextBounds = includeCmdBounds(nextBounds, cmd, db.frames);\n }\n return nextBounds;\n}\n\nfunction pushSection(\n commands: (IconCmd | TextCmd)[],\n bounds: DrawList[\"bounds\"],\n db: RenderDb,\n header: string,\n headerSub: number,\n slots: (DeconstructionEntityFilter | DeconstructionTileFilter | undefined)[],\n rows: number,\n cursorY: number,\n kind: \"entity\" | \"tile\",\n): { bounds: DrawList[\"bounds\"]; nextY: number } {\n const headerCmd = textCommand(header, OUTER_PAD, cursorY + 0.5, HEADER_ENTITY, headerSub);\n commands.push(headerCmd);\n let nextBounds = includeCmdBounds(bounds, headerCmd);\n const gridY = cursorY + HEADER_ROWS;\n nextBounds = pushIconGrid(commands, nextBounds, db, slots, rows, gridY, kind);\n const nextY = gridY + sectionBodyHeight(rows);\n return { bounds: nextBounds, nextY };\n}\n\n/**\n * Plan a Factorio-style deconstruction planner window as a draw list.\n * Empty entity/tile sections are omitted. `trees_and_rocks_only` renders a\n * single tree icon + label (no filter grids). Icon centers snap to the tile grid.\n */\nexport function planDeconstructionPlannerDrawList(\n planner: Record<string, unknown> | DeconstructionPlanner,\n db: RenderDb,\n): DrawList {\n const treesOnly = deconstructionTreesAndRocksOnly(planner);\n const width = gridWidth();\n const commands: (IconCmd | TextCmd)[] = [];\n\n if (treesOnly) {\n const height = OUTER_PAD + ICON_SIZE + OUTER_PAD;\n let bounds: DrawList[\"bounds\"] = { minX: 0, minY: 0, maxX: width, maxY: height };\n const iconPos = tileCenter(OUTER_PAD, OUTER_PAD);\n const treeCmd = treeIconCommand(db, iconPos.x, iconPos.y);\n if (treeCmd) {\n commands.push(treeCmd);\n bounds = includeCmdBounds(bounds, treeCmd, db.frames);\n }\n const label = textCommand(\n \"Trees/rocks only\",\n OUTER_PAD + ICON_SIZE + ICON_GAP,\n OUTER_PAD + 0.5,\n HEADER_ENTITY,\n 0,\n );\n commands.push(label);\n bounds = includeCmdBounds(bounds, label);\n bounds = expandBounds(bounds, 0, 0, width, height);\n commands.sort(compareDrawCmd);\n return { schema: 1, bounds, commands };\n }\n\n const entitySlots = deconstructionEntityFilters(planner);\n const tileSlots = deconstructionTileFilters(planner);\n const entityRows = occupiedRows(DECONSTRUCTION_PLANNER_COLUMNS, lastOccupiedIndex(entitySlots));\n const tileRows = occupiedRows(DECONSTRUCTION_PLANNER_COLUMNS, lastOccupiedIndex(tileSlots));\n const showEntities = entityRows > 0;\n const showTiles = tileRows > 0;\n\n if (!showEntities && !showTiles) {\n const height = OUTER_PAD * 2;\n return {\n schema: 1,\n bounds: { minX: 0, minY: 0, maxX: width, maxY: height },\n commands: [],\n };\n }\n\n const entityMode = formatDeconstructionFilterMode(deconstructionEntityFilterMode(planner));\n const tileMode = formatDeconstructionFilterMode(deconstructionTileFilterMode(planner));\n const tileSelection = formatDeconstructionTileSelectionMode(\n deconstructionTileSelectionMode(planner),\n );\n\n let cursorY = OUTER_PAD;\n let bounds: DrawList[\"bounds\"] = { minX: 0, minY: 0, maxX: width, maxY: OUTER_PAD };\n\n if (showEntities) {\n const section = pushSection(\n commands,\n bounds,\n db,\n `Entities / ${entityMode}`,\n 0,\n entitySlots,\n entityRows,\n cursorY,\n \"entity\",\n );\n bounds = section.bounds;\n cursorY = section.nextY;\n if (showTiles) cursorY += SECTION_GAP;\n }\n\n if (showTiles) {\n const section = pushSection(\n commands,\n bounds,\n db,\n `Tiles / ${tileMode} / ${tileSelection}`,\n 1,\n tileSlots,\n tileRows,\n cursorY,\n \"tile\",\n );\n bounds = section.bounds;\n cursorY = section.nextY;\n }\n\n const height = cursorY + OUTER_PAD;\n bounds = expandBounds(bounds, 0, 0, width, height);\n commands.sort(compareDrawCmd);\n return { schema: 1, bounds, commands };\n}\n","import { altSignalFrame } from \"../alt-mode-signals.js\";\nimport type { SignalId } from \"../types/blueprint.js\";\nimport { compareDrawCmd, RENDER_LAYERS, type DrawList, type IconCmd } from \"../types/draw-list.js\";\nimport type { RenderDb } from \"../types/render-db.js\";\nimport {\n UPGRADE_PLANNER_SLOT_COUNT,\n upgradePlannerMappers,\n type UpgradeMapper,\n type UpgradeMapperDestination,\n type UpgradeMapperSource,\n type UpgradePlanner,\n} from \"../upgrade-planner.js\";\nimport { expandBounds, includeCmdBounds } from \"./bounds.js\";\n\n/** Columns in the Factorio upgrade planner filter window. */\nexport const UPGRADE_PLANNER_COLUMNS = 4;\n\n/** Each mapper slot occupies three 1×1 tiles: from, arrow, to. */\nconst SLOT_TILES = 3;\n/** Empty tiles between adjacent mapper pairs (and between rows). */\nconst PAIR_GAP = 1;\n/** Empty tiles around the full grid. */\nconst OUTER_PAD = 1;\nconst ICON_SIZE = 1;\nconst RIGHT_ARROW_ICON_KEY = \"virtual-signal/right-arrow\";\n\nfunction mapperSignal(\n side: UpgradeMapperSource | UpgradeMapperDestination | undefined,\n): SignalId | undefined {\n if (!side?.name) return undefined;\n return {\n name: side.name,\n type: side.type ?? \"entity\",\n ...(typeof side.quality === \"string\" && side.quality !== \"normal\"\n ? { quality: side.quality }\n : {}),\n };\n}\n\n/** Tile-center for column `tileX` and row `tileY` (integer tile indices). */\nfunction tileCenter(tileX: number, tileY: number): { x: number; y: number } {\n return { x: tileX + 0.5, y: tileY + 0.5 };\n}\n\n/** Rows needed to cover filled mapper slots (trailing empty rows are omitted). */\nfunction occupiedRows(slots: (UpgradeMapper | undefined)[]): number {\n let maxIndex = -1;\n for (let index = 0; index < slots.length; index++) {\n if (slots[index]) maxIndex = index;\n }\n if (maxIndex < 0) return 0;\n return Math.floor(maxIndex / UPGRADE_PLANNER_COLUMNS) + 1;\n}\n\nfunction gridSize(rows: number): { width: number; height: number } {\n const cols = UPGRADE_PLANNER_COLUMNS;\n return {\n width: OUTER_PAD + cols * SLOT_TILES + (cols - 1) * PAIR_GAP + OUTER_PAD,\n height: rows === 0 ? OUTER_PAD * 2 : OUTER_PAD + rows + (rows - 1) * PAIR_GAP + OUTER_PAD,\n };\n}\n\nfunction gridBounds(rows: number): DrawList[\"bounds\"] {\n const { width, height } = gridSize(rows);\n return { minX: 0, minY: 0, maxX: width, maxY: height };\n}\n\nfunction mapperIconCommand(\n db: RenderDb,\n side: UpgradeMapperSource | UpgradeMapperDestination | undefined,\n x: number,\n y: number,\n entity: number,\n sub: number,\n): IconCmd | undefined {\n const signal = mapperSignal(side);\n if (!signal) return undefined;\n const frame = altSignalFrame(db, signal) ?? db.icons[\"utility/missing-icon\"];\n if (frame === undefined) return undefined;\n return {\n kind: \"icon\",\n layer: RENDER_LAYERS.icons,\n sortY: y,\n sortX: x,\n entity,\n sub,\n frame,\n x,\n y,\n size: ICON_SIZE,\n };\n}\n\nfunction arrowCommand(db: RenderDb, x: number, y: number, entity: number): IconCmd | undefined {\n const frame = db.icons[RIGHT_ARROW_ICON_KEY] ?? db.icons[\"utility/missing-icon\"];\n if (frame === undefined) return undefined;\n return {\n kind: \"icon\",\n layer: RENDER_LAYERS.icons,\n sortY: y,\n sortX: x,\n entity,\n sub: 1,\n frame,\n x,\n y,\n size: ICON_SIZE,\n };\n}\n\n/**\n * Plan a Factorio-style upgrade planner filter window as a draw list:\n * filled slots as from → right-arrow → to on a 1×1 tile grid (4 columns),\n * with 1-tile gaps between pairs and 1-tile outer padding.\n * Height covers only rows up to the last occupied mapper index.\n */\nexport function planUpgradePlannerDrawList(\n planner: Record<string, unknown> | UpgradePlanner,\n db: RenderDb,\n): DrawList {\n const slots = upgradePlannerMappers(planner);\n const rows = occupiedRows(slots);\n const commands: IconCmd[] = [];\n let bounds: DrawList[\"bounds\"] | null = gridBounds(rows);\n const colStride = SLOT_TILES + PAIR_GAP;\n const rowStride = 1 + PAIR_GAP;\n const slotLimit = Math.min(UPGRADE_PLANNER_SLOT_COUNT, rows * UPGRADE_PLANNER_COLUMNS);\n\n for (let index = 0; index < slotLimit; index++) {\n const mapper = slots[index];\n if (!mapper) continue;\n const col = index % UPGRADE_PLANNER_COLUMNS;\n const row = Math.floor(index / UPGRADE_PLANNER_COLUMNS);\n const baseX = OUTER_PAD + col * colStride;\n const baseY = OUTER_PAD + row * rowStride;\n const entity = index + 1;\n\n const fromPos = tileCenter(baseX, baseY);\n const fromCmd = mapperIconCommand(db, mapper.from, fromPos.x, fromPos.y, entity, 0);\n if (fromCmd) {\n commands.push(fromCmd);\n bounds = includeCmdBounds(bounds, fromCmd, db.frames);\n }\n\n const arrowPos = tileCenter(baseX + 1, baseY);\n const arrowCmd = arrowCommand(db, arrowPos.x, arrowPos.y, entity);\n if (arrowCmd) {\n commands.push(arrowCmd);\n bounds = includeCmdBounds(bounds, arrowCmd, db.frames);\n }\n\n const toPos = tileCenter(baseX + 2, baseY);\n const toCmd = mapperIconCommand(db, mapper.to, toPos.x, toPos.y, entity, 2);\n if (toCmd) {\n commands.push(toCmd);\n bounds = includeCmdBounds(bounds, toCmd, db.frames);\n }\n }\n\n if (!bounds) {\n bounds = gridBounds(rows);\n } else {\n const grid = gridBounds(rows);\n bounds = expandBounds(\n bounds,\n grid.minX,\n grid.minY,\n grid.maxX - grid.minX,\n grid.maxY - grid.minY,\n );\n }\n\n commands.sort(compareDrawCmd);\n return { schema: 1, bounds, commands };\n}\n","/**\n * Plan Factorio 2.1 cargo-bay connection graphics (tileset + bridges) between\n * space-platform-hub, cargo-bay, and cargo-landing-pad footprints.\n */\n\nimport type { Blueprint, BlueprintEntity } from \"./types/blueprint.js\";\nimport { type DrawCmd, RENDER_LAYERS, type SpriteCmd } from \"./types/draw-list.js\";\nimport type {\n CargoBayConnectionCell,\n CargoBayConnections,\n EntityRenderDef,\n FrameMeta,\n RenderDb,\n SpriteVariant,\n} from \"./types/render-db.js\";\n\nconst CONNECTABLE_PROTOS = new Set([\"space-platform-hub\", \"cargo-bay\", \"cargo-landing-pad\"]);\n/** Cargo bays are evaluated on Factorio's forced 2x2 build/connection grid. */\nconst CONNECTION_GRID_SIZE = 2;\n\n/** 8-neighbor offsets clockwise from top-left (Factorio CargoBayConnections docs). */\nconst NEIGHBOR8: readonly [number, number][] = [\n [-1, -1], // 0 top-left\n [0, -1], // 1 top\n [1, -1], // 2 top-right\n [1, 0], // 3 right\n [1, 1], // 4 bottom-right\n [0, 1], // 5 bottom\n [-1, 1], // 6 bottom-left\n [-1, 0], // 7 left\n];\n\nfunction tileKey(x: number, y: number): string {\n return `${x},${y}`;\n}\n\nfunction hashTile(x: number, y: number): number {\n // Same family as tile material hashing in plan.ts — stable across runs.\n let h = (Math.imul(x | 0, 374761393) + Math.imul(y | 0, 668265263)) | 0;\n h = Math.imul(h ^ (h >>> 13), 1274126177);\n return (h ^ (h >>> 16)) >>> 0;\n}\n\ninterface ConnectionCellPosition {\n /** Logical coordinates on the 2x2 cargo-connection grid. */\n gridX: number;\n gridY: number;\n /** World-space center of the 2x2 cell, in tile units. */\n x: number;\n y: number;\n}\n\nfunction footprintCells(entity: BlueprintEntity, def: EntityRenderDef): ConnectionCellPosition[] {\n const [[x1, y1], [x2, y2]] = def.collisionBox;\n const minX = Math.floor(entity.position.x + x1 + 1e-6);\n const maxX = Math.ceil(entity.position.x + x2 - 1e-6) - 1;\n const minY = Math.floor(entity.position.y + y1 + 1e-6);\n const maxY = Math.ceil(entity.position.y + y2 - 1e-6) - 1;\n const cells: ConnectionCellPosition[] = [];\n for (let y = minY; y <= maxY; y += CONNECTION_GRID_SIZE) {\n for (let x = minX; x <= maxX; x += CONNECTION_GRID_SIZE) {\n const centerX = x + CONNECTION_GRID_SIZE / 2;\n const centerY = y + CONNECTION_GRID_SIZE / 2;\n cells.push({\n gridX: Math.floor(centerX / CONNECTION_GRID_SIZE),\n gridY: Math.floor(centerY / CONNECTION_GRID_SIZE),\n x: centerX,\n y: centerY,\n });\n }\n }\n return cells;\n}\n\nfunction spriteDest(\n posX: number,\n posY: number,\n frame: FrameMeta,\n variant: SpriteVariant,\n): { x: number; y: number; w: number; h: number } {\n const w = (frame.sw * variant.scale) / 32;\n const h = (frame.sh * variant.scale * (variant.scaleY ?? 1)) / 32;\n const cx = posX + variant.shift[0];\n const cy = posY + variant.shift[1];\n return { x: cx - w / 2, y: cy - h / 2, w, h };\n}\n\nfunction pickConnections(\n def: EntityRenderDef,\n preferPlatform: boolean,\n): CargoBayConnections | undefined {\n return preferPlatform\n ? (def.data?.cargoBayConnectionsPlatform ?? def.data?.cargoBayConnections)\n : (def.data?.cargoBayConnections ?? def.data?.cargoBayConnectionsPlatform);\n}\n\nfunction pickCellVariation(\n groups: CargoBayConnectionCell[][],\n tx: number,\n ty: number,\n): CargoBayConnectionCell | undefined {\n if (groups.length === 0) return undefined;\n const groupIndex = groups.length > 1 ? (tx + ty) & 1 : 0;\n const group = groups[groupIndex] ?? groups[0];\n if (!group || group.length === 0) return undefined;\n const variation = group[hashTile(tx, ty) % group.length];\n return variation;\n}\n\nfunction emitCell(\n cell: CargoBayConnectionCell,\n cx: number,\n cy: number,\n db: RenderDb,\n entityNumber: number,\n subBase: number,\n sortY: number,\n sortX: number,\n commands: DrawCmd[],\n): number {\n let sub = subBase;\n for (const layer of cell.layers) {\n const frame = db.frames[layer.variant.frame];\n if (!frame) continue;\n const dest = spriteDest(cx, cy, frame, layer.variant);\n const layerName = layer.layer;\n const cmd: SpriteCmd = {\n kind: \"sprite\",\n layer: RENDER_LAYERS[layerName],\n sortY,\n sortX,\n entity: entityNumber,\n sub: sub++,\n frame: layer.variant.frame,\n x: dest.x,\n y: dest.y,\n w: dest.w,\n h: dest.h,\n };\n if (layer.variant.drawAsShadow) cmd.shadow = true;\n if (layer.variant.tint) cmd.tint = layer.variant.tint;\n commands.push(cmd);\n }\n return sub;\n}\n\nfunction occupancyMask(occ: Set<string>, tx: number, ty: number): number {\n let mask = 0;\n for (let bit = 0; bit < 8; bit++) {\n const [dx, dy] = NEIGHBOR8[bit]!;\n if (occ.has(tileKey(tx + dx, ty + dy))) mask |= 1 << bit;\n }\n return mask;\n}\n\ninterface ConnectableInfo {\n entity: BlueprintEntity;\n def: EntityRenderDef;\n connections: CargoBayConnections;\n cells: ConnectionCellPosition[];\n minX: number;\n maxX: number;\n minY: number;\n maxY: number;\n}\n\nfunction buildConnectables(\n bp: Blueprint,\n db: RenderDb,\n preferPlatform: boolean,\n): ConnectableInfo[] {\n const out: ConnectableInfo[] = [];\n for (const entity of bp.entities ?? []) {\n const def = db.entities[entity.name];\n if (!def || (!CONNECTABLE_PROTOS.has(def.protoType) && !CONNECTABLE_PROTOS.has(entity.name))) {\n continue;\n }\n // Match by entity name (protoType may be generic \"simple\" distill kind — use name).\n if (\n entity.name !== \"space-platform-hub\" &&\n entity.name !== \"cargo-bay\" &&\n entity.name !== \"cargo-landing-pad\"\n ) {\n continue;\n }\n const connections = pickConnections(def, preferPlatform);\n if (!connections) continue;\n const cells = footprintCells(entity, def);\n if (cells.length === 0) continue;\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n const [[x1, y1], [x2, y2]] = def.collisionBox;\n minX = Math.floor(entity.position.x + x1 + 1e-6);\n maxX = Math.ceil(entity.position.x + x2 - 1e-6) - 1;\n minY = Math.floor(entity.position.y + y1 + 1e-6);\n maxY = Math.ceil(entity.position.y + y2 - 1e-6) - 1;\n out.push({ entity, def, connections, cells, minX, maxX, minY, maxY });\n }\n return out;\n}\n\n/**\n * Emit cargo-bay connection tileset + bridge sprites for the blueprint.\n * Returns the number of commands appended.\n */\nexport function emitCargoBayConnections(\n bp: Blueprint,\n db: RenderDb,\n preferPlatform: boolean,\n commands: DrawCmd[],\n): void {\n const connectables = buildConnectables(bp, db, preferPlatform);\n if (connectables.length === 0) return;\n\n const occ = new Set<string>();\n const owner = new Map<string, { connectable: ConnectableInfo; cell: ConnectionCellPosition }>();\n for (const c of connectables) {\n for (const cell of c.cells) {\n const k = tileKey(cell.gridX, cell.gridY);\n occ.add(k);\n owner.set(k, { connectable: c, cell });\n }\n }\n\n let sub = 10_000;\n const connRef = connectables[0]!.connections;\n\n // CargoBayConnections tiles are the connectable body's lower/perimeter art,\n // not just seam decoration. Factorio evaluates the 8-neighbour mask for\n // every occupied 2x2 footprint cell; interior masks map to 0/undefined while\n // boundary masks select walls and corners. The sprites are authored for this\n // 2-tile cadence—emitting them once per world tile makes the body one ring\n // too large and overlaps the same art too densely.\n for (const key of occ) {\n const [xs, ys] = key.split(\",\");\n const gridX = Number(xs);\n const gridY = Number(ys);\n const mask = occupancyMask(occ, gridX, gridY);\n const mapped = connRef.tilesetMapping[String(mask)];\n if (mapped == null || mapped === 0) continue;\n const indices = Array.isArray(mapped) ? mapped : [mapped];\n const owned = owner.get(key);\n if (!owned) continue;\n const { cell, connectable: cellOwner } = owned;\n const sortY = cellOwner.entity.position.y + cellOwner.def.collisionBox[1][1];\n const sortX = cellOwner.entity.position.x;\n\n for (const oneBased of indices) {\n if (oneBased === 0) continue;\n const groups = connRef.tileset[oneBased - 1];\n if (!groups) continue;\n const variation = pickCellVariation(groups, gridX, gridY);\n if (!variation) continue;\n sub = emitCell(\n variation,\n cell.x,\n cell.y,\n db,\n cellOwner.entity.entity_number,\n sub,\n sortY,\n sortX,\n commands,\n );\n }\n }\n\n // Bridges between orthogonally adjacent connectable pairs.\n const hBridges: SharedEdge[] = [];\n const vBridges: SharedEdge[] = [];\n for (let i = 0; i < connectables.length; i++) {\n for (let j = i + 1; j < connectables.length; j++) {\n const emitted = emitBridgePair(connectables[i]!, connectables[j]!, db, commands, () => {\n const s = sub;\n sub += 20;\n return s;\n });\n if (emitted) {\n if (emitted.axis === \"h\") hBridges.push(emitted);\n else vBridges.push(emitted);\n }\n }\n }\n\n // Place bridge_crossing where H and V bridges meet and all four quadrants\n // are occupied (a true 4-way junction — not an L-corner).\n const crossingCells = connRef.bridges.crossing;\n if (crossingCells.length > 0) {\n const covered = (tx: number, ty: number): boolean =>\n connectables.some((c) => tx >= c.minX && tx <= c.maxX && ty >= c.minY && ty <= c.maxY);\n const crossingPoints = new Map<string, { x: number; y: number }>();\n for (const h of hBridges) {\n for (const v of vBridges) {\n const cx = h.midX;\n const cy = v.midY;\n if (cy < h.y0 || cy > h.y1 + 1) continue;\n if (cx < v.x0 || cx > v.x1 + 1) continue;\n if (\n !covered(cx - 1, cy - 1) ||\n !covered(cx, cy - 1) ||\n !covered(cx - 1, cy) ||\n !covered(cx, cy)\n ) {\n continue;\n }\n crossingPoints.set(tileKey(cx, cy), { x: cx, y: cy });\n }\n }\n for (const { x, y } of crossingPoints.values()) {\n const cell = crossingCells[hashTile(Math.floor(x), Math.floor(y)) % crossingCells.length]!;\n sub = emitCell(cell, x, y, db, connectables[0]!.entity.entity_number, sub, y, x, commands);\n }\n }\n}\n\ninterface SharedEdge {\n axis: \"h\" | \"v\";\n x0: number;\n x1: number;\n y0: number;\n y1: number;\n midX: number;\n midY: number;\n}\n\nfunction sharedEdge(a: ConnectableInfo, b: ConnectableInfo): SharedEdge | null {\n // Horizontal adjacency: a's right + 1 == b's left (or swap)\n if (a.maxX + 1 === b.minX || b.maxX + 1 === a.minX) {\n const left = a.maxX + 1 === b.minX ? a : b;\n const right = left === a ? b : a;\n const y0 = Math.max(left.minY, right.minY);\n const y1 = Math.min(left.maxY, right.maxY);\n if (y1 < y0) return null;\n const midX = left.maxX + 1;\n const midY = (y0 + y1 + 1) / 2;\n return { axis: \"h\", x0: left.maxX, x1: right.minX, y0, y1, midX, midY };\n }\n // Vertical adjacency\n if (a.maxY + 1 === b.minY || b.maxY + 1 === a.minY) {\n const top = a.maxY + 1 === b.minY ? a : b;\n const bottom = top === a ? b : a;\n const x0 = Math.max(top.minX, bottom.minX);\n const x1 = Math.min(top.maxX, bottom.maxX);\n if (x1 < x0) return null;\n const midX = (x0 + x1 + 1) / 2;\n const midY = top.maxY + 1;\n return { axis: \"v\", x0, x1, y0: top.maxY, y1: bottom.minY, midX, midY };\n }\n return null;\n}\n\nfunction emitBridgePair(\n a: ConnectableInfo,\n b: ConnectableInfo,\n db: RenderDb,\n commands: DrawCmd[],\n nextSub: () => number,\n): SharedEdge | null {\n const edge = sharedEdge(a, b);\n if (!edge) return null;\n const span = edge.axis === \"h\" ? edge.y1 - edge.y0 + 1 : edge.x1 - edge.x0 + 1;\n const bridges = a.connections.bridges;\n const wide = span >= 4;\n const cells =\n edge.axis === \"h\"\n ? wide\n ? bridges.horizontalWide\n : bridges.horizontalNarrow\n : wide\n ? bridges.verticalWide\n : bridges.verticalNarrow;\n if (cells.length === 0) return null;\n const cell = cells[hashTile(Math.floor(edge.midX), Math.floor(edge.midY)) % cells.length]!;\n const sortY = Math.max(\n a.entity.position.y + a.def.collisionBox[1][1],\n b.entity.position.y + b.def.collisionBox[1][1],\n );\n const sortX = (a.entity.position.x + b.entity.position.x) / 2;\n emitCell(\n cell,\n edge.midX,\n edge.midY,\n db,\n a.entity.entity_number,\n nextSub(),\n sortY,\n sortX,\n commands,\n );\n return edge;\n}\n\n/** @internal exported for tests */\nexport const _cargoBayConnectionsTest = {\n occupancyMask,\n sharedEdge,\n footprintCells,\n CONNECTABLE_PROTOS,\n CONNECTION_GRID_SIZE,\n NEIGHBOR8,\n};\n","import { type BeltOccupant, beltReaderSlots } from \"../resolve.js\";\nimport type { Blueprint, BlueprintEntity } from \"../types/blueprint.js\";\nimport { type DrawCmd, type DrawList, RENDER_LAYERS, type SpriteCmd } from \"../types/draw-list.js\";\nimport type {\n BeltReaderGraphics,\n EntityRenderDef,\n RenderDb,\n RenderLayerName,\n} from \"../types/render-db.js\";\nimport { includeCmdBounds, spriteDest } from \"./bounds.js\";\n\n/** Official belt_reader layers (already above transport-belt in Factorio enum). */\nfunction paintBeltReaderLayer(official: RenderLayerName): number {\n return RENDER_LAYERS[official] ?? RENDER_LAYERS[\"transport-belt-reader\"];\n}\n\nfunction beltReaderLayerOrder(name: RenderLayerName): number {\n return RENDER_LAYERS[name] ?? 0;\n}\n\n/**\n * Emit whole-belt-reader side skirts for entire_belt_hold lines.\n * Sheet is band×NESW; each belt may paint multiple edge frames.\n * Underground belts on the line get skirts too (under the hood).\n */\nexport function emitBeltReaders(\n bp: Blueprint,\n db: RenderDb,\n byNumber: Map<number, { entity: BlueprintEntity; def: EntityRenderDef }>,\n beltIndex: Map<string, BeltOccupant[]>,\n readerEntities: Set<number>,\n commands: DrawCmd[],\n bounds: DrawList[\"bounds\"] | null,\n): DrawList[\"bounds\"] | null {\n if (readerEntities.size === 0) return bounds;\n let b = bounds;\n\n for (const entityNumber of readerEntities) {\n const entry = byNumber.get(entityNumber);\n if (!entry) continue;\n const { entity, def } = entry;\n if (def.kind !== \"belt\" && def.kind !== \"underground-belt\") continue;\n const graphics: BeltReaderGraphics | undefined = def.data?.beltReaderGraphics;\n if (!graphics?.layers?.length) continue;\n\n const slots = beltReaderSlots(entity, def, beltIndex, readerEntities);\n // Official order: endings < floor-mechanics < transport-belt-reader < object.\n // Skirts stay under UG hoods (object) so they appear to run through — same as in-game.\n const layers = [...graphics.layers].sort(\n (a, b) => beltReaderLayerOrder(a.layer) - beltReaderLayerOrder(b.layer),\n );\n\n // Per-entity sub (not global): sort is (layer, sortY, sortX, entity, sub), and belt\n // cages use sub≥50 on transport-belt-circuit-connector. A global counter\n // pushed later reader entities above 50 so skirts painted over cages.\n let sub = 10;\n\n for (const slot of slots) {\n for (const layer of layers) {\n const variant = layer.variants[slot.band]?.[slot.frame];\n if (!variant) continue;\n const frame = db.frames[variant.frame];\n if (!frame) continue;\n const dest = spriteDest(entity.position.x, entity.position.y, frame, variant, slot.shift);\n const isShadow = variant.drawAsShadow === true;\n const cmd: SpriteCmd = {\n kind: \"sprite\",\n layer: isShadow ? RENDER_LAYERS.shadow : paintBeltReaderLayer(layer.layer),\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: sub++,\n frame: variant.frame,\n x: dest.x,\n y: dest.y,\n w: dest.w,\n h: dest.h,\n };\n if (variant.tint) cmd.tint = variant.tint;\n if (isShadow) cmd.shadow = true;\n // Slot flip (ending mirror) XOR variant flip from distill.\n if (Boolean(variant.flipX) !== Boolean(slot.flipX)) cmd.flipX = true;\n if (Boolean(variant.flipY) !== Boolean(slot.flipY)) cmd.flipY = true;\n if (variant.rotation) cmd.rotation = variant.rotation;\n commands.push(cmd);\n b = includeCmdBounds(b, cmd, db.frames);\n }\n }\n }\n return b;\n}\n","import {\n type BeltOccupant,\n beltCircuitConnectorFrame,\n beltCircuitConnectorVariation,\n beltConnectorBackPatchIndex,\n dir16ToIndex,\n isBeltCircuitInputEnabled,\n isBeltCircuitOutputEnabled,\n} from \"../resolve.js\";\nimport type { Blueprint, BlueprintEntity } from \"../types/blueprint.js\";\nimport { type DrawCmd, type DrawList, RENDER_LAYERS, type SpriteCmd } from \"../types/draw-list.js\";\nimport type {\n BeltConnectorGraphics,\n CombinatorGraphics,\n EntityRenderDef,\n RenderDb,\n SpriteVariant,\n WireConnectorGraphics,\n} from \"../types/render-db.js\";\nimport { includeCmdBounds, spriteDest } from \"./bounds.js\";\n\n/** Entities that appear in any `bp.wires` tuple (FBE generateConnector). */\nfunction wiredEntityNumbers(bp: Blueprint): Set<number> {\n const out = new Set<number>();\n for (const w of bp.wires ?? []) {\n if (!Array.isArray(w) || w.length < 4) continue;\n out.add(w[0]);\n out.add(w[2]);\n }\n return out;\n}\n\nfunction combinatorDisplayKey(entity: BlueprintEntity, def: EntityRenderDef): string | undefined {\n const behavior = entity.control_behavior;\n if (!behavior) return undefined;\n if (def.protoType === \"arithmetic-combinator\") {\n const conditions = behavior.arithmetic_conditions as Record<string, unknown> | undefined;\n return typeof conditions?.operation === \"string\" ? conditions.operation : undefined;\n }\n if (def.protoType === \"decider-combinator\") {\n const conditions = behavior.decider_conditions as\n | { conditions?: Record<string, unknown>[]; comparator?: unknown }\n | undefined;\n // 2.x nests conditions; 1.x keeps comparator on the root object.\n const nested = conditions?.conditions?.[0]?.comparator;\n const flat = conditions?.comparator;\n const comparator =\n typeof nested === \"string\" ? nested : typeof flat === \"string\" ? flat : undefined;\n if (typeof comparator !== \"string\") return undefined;\n return { \"!=\": \"≠\", \"<=\": \"≤\", \">=\": \"≥\" }[comparator] ?? comparator;\n }\n if (def.protoType === \"selector-combinator\") {\n if (behavior.operation === \"select\") return behavior.select_max === false ? \"min\" : \"max\";\n return typeof behavior.operation === \"string\" ? behavior.operation : undefined;\n }\n return undefined;\n}\n\nexport function emitCombinatorDisplay(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n db: RenderDb,\n commands: DrawCmd[],\n bounds: DrawList[\"bounds\"] | null,\n): DrawList[\"bounds\"] | null {\n const key = combinatorDisplayKey(entity, def);\n const graphics: CombinatorGraphics | undefined = def.data?.combinatorGraphics;\n const variants = key ? graphics?.symbols?.[key] : undefined;\n if (!variants) return bounds;\n const variant = variants[dir16ToIndex(entity.direction ?? 0, \"direction4\")] ?? variants[0];\n if (!variant) return bounds;\n const frame = db.frames[variant.frame];\n if (!frame) return bounds;\n const dest = spriteDest(entity.position.x, entity.position.y, frame, variant);\n const cmd: SpriteCmd = {\n kind: \"sprite\",\n layer: RENDER_LAYERS[\"higher-object-above\"],\n sortY: entity.position.y + def.collisionBox[1][1],\n sortX: entity.position.x,\n entity: entity.entity_number,\n sub: 90,\n frame: variant.frame,\n x: dest.x,\n y: dest.y,\n w: dest.w,\n h: dest.h,\n };\n commands.push(cmd);\n return includeCmdBounds(bounds, cmd, db.frames);\n}\n\nconst CCM_DRAW_ORDER = [\n \"connector_shadow\",\n \"connector_main\",\n \"wire_pins_shadow\",\n \"wire_pins\",\n \"led_blue_off\",\n] as const;\n\nfunction connectorDirIndex(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n graphics: WireConnectorGraphics,\n poleDirs: Map<number, number>,\n): number {\n const direction =\n def.protoType === \"electric-pole\"\n ? (poleDirs.get(entity.entity_number) ?? entity.direction ?? 0)\n : (entity.direction ?? 0);\n const indexing = graphics.indexing ?? \"direction4\";\n return dir16ToIndex(direction, indexing === \"single\" ? \"direction4\" : indexing);\n}\n\n/**\n * Emit circuit-connector decorations (CCM) for entities that have wire links.\n * Paint order matches FBE: shadow → main → pins → led_blue_off.\n */\nexport function emitCircuitConnectors(\n bp: Blueprint,\n db: RenderDb,\n byNumber: Map<number, { entity: BlueprintEntity; def: EntityRenderDef }>,\n poleDirs: Map<number, number>,\n commands: DrawCmd[],\n bounds: DrawList[\"bounds\"] | null,\n): DrawList[\"bounds\"] | null {\n const wired = wiredEntityNumbers(bp);\n if (wired.size === 0) return bounds;\n let b = bounds;\n for (const entityNumber of wired) {\n const entry = byNumber.get(entityNumber);\n if (!entry) continue;\n const { entity, def } = entry;\n const graphics: WireConnectorGraphics | undefined = def.data?.wireConnectorGraphics;\n if (!graphics?.layers) continue;\n const index = connectorDirIndex(entity, def, graphics, poleDirs);\n const sortYObject = entity.position.y + def.collisionBox[1][1];\n const sortXObject = entity.position.x;\n let sub = 100; // after body graphics / alt icons\n for (const key of CCM_DRAW_ORDER) {\n // Logistic chests expose bare red/green wire pegs in-game. Their generic\n // connector base and status LED must not be painted over the chest body.\n if (\n def.protoType === \"logistic-container\" &&\n key !== \"wire_pins\" &&\n key !== \"wire_pins_shadow\"\n ) {\n continue;\n }\n const variants = graphics.layers[key];\n if (!variants) continue;\n const variant = variants[index] ?? variants[0];\n if (!variant) continue;\n const frame = db.frames[variant.frame];\n if (!frame) continue;\n const dest = spriteDest(entity.position.x, entity.position.y, frame, variant);\n const isShadow = key.endsWith(\"_shadow\") || variant.drawAsShadow === true;\n const cmd: SpriteCmd = {\n kind: \"sprite\",\n layer: isShadow ? RENDER_LAYERS.shadow : RENDER_LAYERS[\"higher-object-above\"],\n sortY: isShadow ? 0 : sortYObject,\n sortX: isShadow ? 0 : sortXObject,\n entity: entity.entity_number,\n sub: sub++,\n frame: variant.frame,\n x: dest.x,\n y: dest.y,\n w: dest.w,\n h: dest.h,\n };\n if (variant.tint) cmd.tint = variant.tint;\n if (isShadow) cmd.shadow = true;\n if (variant.flipX) cmd.flipX = true;\n if (variant.flipY) cmd.flipY = true;\n if (variant.rotation) cmd.rotation = variant.rotation;\n commands.push(cmd);\n b = includeCmdBounds(b, cmd, db.frames);\n }\n }\n return b;\n}\n\n/**\n * Emit transport-belt circuit connector cage + LEDs on\n * transport-belt-circuit-connector (35), above transport-belt (27).\n *\n * Paint: shadow → back_patch → main (cage+pegs) → H/V décor wires → LEDs.\n *\n * The four sheet frames encode behavior state (none/output/input/both), not\n * direction. Décor plates reconstruct the selected source frame after distill\n * split its baked coils from the clean cage. LEDs use the same behavior state\n * (output → red/green; input → blue).\n */\nexport function emitBeltCircuitConnectors(\n bp: Blueprint,\n db: RenderDb,\n byNumber: Map<number, { entity: BlueprintEntity; def: EntityRenderDef }>,\n beltVariations: Map<number, number>,\n commands: DrawCmd[],\n bounds: DrawList[\"bounds\"] | null,\n): DrawList[\"bounds\"] | null {\n const wired = wiredEntityNumbers(bp);\n if (wired.size === 0) return bounds;\n let b = bounds;\n const layer = RENDER_LAYERS[\"transport-belt-circuit-connector\"];\n\n for (const entityNumber of wired) {\n const entry = byNumber.get(entityNumber);\n if (!entry || entry.def.kind !== \"belt\") continue;\n const { entity, def } = entry;\n const graphics: BeltConnectorGraphics | undefined = def.data?.beltConnectorGraphics;\n if (!graphics?.layers) continue;\n\n const variation = beltVariations.get(entityNumber) ?? 0;\n const connectorFrame = beltCircuitConnectorFrame(entity);\n let sub = 50;\n const outputOn = isBeltCircuitOutputEnabled(entity);\n const inputOn = isBeltCircuitInputEnabled(entity);\n\n const pushVariant = (variant: SpriteVariant | null | undefined): void => {\n if (!variant) return;\n const frame = db.frames[variant.frame];\n if (!frame) return;\n const dest = spriteDest(entity.position.x, entity.position.y, frame, variant);\n const isShadow = variant.drawAsShadow === true;\n // Same layer as the cage; sub order keeps shadow under main/LEDs.\n const cmd: SpriteCmd = {\n kind: \"sprite\",\n layer,\n sortY: 0,\n sortX: 0,\n entity: entity.entity_number,\n sub: sub++,\n frame: variant.frame,\n x: dest.x,\n y: dest.y,\n w: dest.w,\n h: dest.h,\n };\n if (variant.tint) cmd.tint = variant.tint;\n if (isShadow) cmd.shadow = true;\n if (variant.flipX) cmd.flipX = true;\n if (variant.flipY) cmd.flipY = true;\n if (variant.rotation) cmd.rotation = variant.rotation;\n commands.push(cmd);\n b = includeCmdBounds(b, cmd, db.frames);\n };\n\n const shadowRow = graphics.layers.frame_shadow?.[variation];\n pushVariant(shadowRow?.[connectorFrame] ?? shadowRow?.[0]);\n\n const backPatch = graphics.layers.frame_back_patch;\n if (backPatch) {\n pushVariant(backPatch[beltConnectorBackPatchIndex(variation)] ?? backPatch[0]);\n }\n\n const mainRow = graphics.layers.frame_main?.[variation];\n pushVariant(mainRow?.[connectorFrame] ?? mainRow?.[0]);\n\n // Re-apply every décor plate present in the selected behavior-state frame.\n const hRow = graphics.layers.wire_horizontal?.[variation];\n const vRow = graphics.layers.wire_vertical?.[variation];\n pushVariant(hRow?.[connectorFrame] ?? hRow?.[0]);\n pushVariant(vRow?.[connectorFrame] ?? vRow?.[0]);\n\n const ledKeys: (\"led_red\" | \"led_green\" | \"led_blue\")[] = [];\n if (outputOn) ledKeys.push(\"led_red\", \"led_green\");\n if (inputOn) ledKeys.push(\"led_blue\");\n for (const ledKey of ledKeys) {\n const leds = graphics.layers[ledKey];\n if (!leds) continue;\n pushVariant(leds[variation] ?? leds[0]);\n }\n }\n return b;\n}\n\nexport function buildBeltConnectorVariations(\n bp: Blueprint,\n byNumber: Map<number, { entity: BlueprintEntity; def: EntityRenderDef }>,\n beltIndex: Map<string, BeltOccupant[]>,\n): Map<number, number> {\n const out = new Map<number, number>();\n for (const entityNumber of wiredEntityNumbers(bp)) {\n const entry = byNumber.get(entityNumber);\n if (!entry || entry.def.kind !== \"belt\") continue;\n out.set(entityNumber, beltCircuitConnectorVariation(entry.entity, beltIndex));\n }\n return out;\n}\n","import { cardinalDirection } from \"../resolve.js\";\nimport type { Blueprint, BlueprintEntity } from \"../types/blueprint.js\";\nimport { type DrawCmd, type DrawList, RENDER_LAYERS, type SpriteCmd } from \"../types/draw-list.js\";\nimport type {\n EntityRenderDef,\n FrameMeta,\n PipeCoverGraphics,\n RenderDb,\n RenderLayerName,\n SpriteVariant,\n} from \"../types/render-db.js\";\nimport { includeCmdBounds, spriteDest } from \"./bounds.js\";\n\n/** Tile-center key matching resolve.ts neighbor grid. */\nfunction tileKey(x: number, y: number): string {\n return `${Math.round(x * 1000) / 1000},${Math.round(y * 1000) / 1000}`;\n}\n\nfunction buildEntityGrid(entities: BlueprintEntity[]): Map<string, BlueprintEntity[]> {\n const grid = new Map<string, BlueprintEntity[]>();\n for (const e of entities) {\n const key = tileKey(e.position.x, e.position.y);\n const list = grid.get(key);\n if (list) list.push(e);\n else grid.set(key, [e]);\n }\n return grid;\n}\n\n/** direction4 index (N=0,E=1,S=2,W=3) from entity→pipe-tile offset. */\nfunction coverDirIndex(ox: number, oy: number): 0 | 1 | 2 | 3 {\n if (Math.abs(ox) >= Math.abs(oy)) return ox > 0 ? 1 : 3;\n return oy > 0 ? 2 : 0;\n}\n\n/** True when the adjacent port tile has a pipe / pipe-to-ground / fluid entity. */\nfunction fluidPortOccupied(\n grid: Map<string, BlueprintEntity[]>,\n db: RenderDb,\n pipeX: number,\n pipeY: number,\n): boolean {\n const neighbors = grid.get(tileKey(pipeX, pipeY));\n if (!neighbors) return false;\n for (const n of neighbors) {\n const nd = db.entities[n.name];\n if (!nd) continue;\n if (nd.kind === \"pipe\") return true;\n if (nd.protoType === \"pipe-to-ground\" || n.name === \"pipe-to-ground\") return true;\n if (nd.data?.fluidConnections) return true;\n }\n return false;\n}\n\nfunction pushPipeCoverSprite(\n commands: DrawCmd[],\n bounds: DrawList[\"bounds\"] | null,\n entity: BlueprintEntity,\n frame: FrameMeta,\n variant: SpriteVariant,\n cx: number,\n cy: number,\n sortY: number,\n sortX: number,\n sub: number,\n): DrawList[\"bounds\"] {\n const dest = spriteDest(cx, cy, frame, variant);\n // Unconnected caps sit on `object` (FBSR Layer.OBJECT at the adjacent tile).\n const layerName: RenderLayerName = variant.drawAsShadow ? \"shadow\" : \"object\";\n const cmd: SpriteCmd = {\n kind: \"sprite\",\n layer: RENDER_LAYERS[layerName],\n sortY: variant.drawAsShadow ? 0 : sortY,\n sortX: variant.drawAsShadow ? 0 : sortX,\n entity: entity.entity_number,\n sub,\n frame: variant.frame,\n x: dest.x,\n y: dest.y,\n w: dest.w,\n h: dest.h,\n };\n if (variant.drawAsShadow) cmd.shadow = true;\n commands.push(cmd);\n return includeCmdBounds(bounds, cmd, undefined, frame);\n}\n\n/**\n * Draw fluid-box pipe covers on each *unconnected* port's adjacent tile.\n * Factorio: `pipe_covers` are \"the pictures to show when no FluidBox is\n * connected\" — caps sealing open flanges (FBSR: `!isPipeConnected`).\n */\nexport function emitPipeCovers(\n bp: Blueprint,\n db: RenderDb,\n byNumber: Map<number, { entity: BlueprintEntity; def: EntityRenderDef }>,\n commands: DrawCmd[],\n bounds: DrawList[\"bounds\"] | null,\n): DrawList[\"bounds\"] | null {\n const grid = buildEntityGrid(bp.entities ?? []);\n let b = bounds;\n\n for (const { entity, def } of byNumber.values()) {\n // Pipes already draw their own joints; covers are for machine fluid-box flanges.\n if (def.kind === \"pipe\" || def.protoType === \"pipe-to-ground\") continue;\n const pc: PipeCoverGraphics | undefined = def.data?.pipeCovers;\n const fc = def.data?.fluidConnections;\n if (!pc?.covers || !fc) continue;\n\n const d = cardinalDirection(entity.direction ?? 0);\n // Match owning entity y-sort so covers composite with the machine cut.\n const sortY = entity.position.y + def.collisionBox[1][1];\n const sortX = entity.position.x;\n for (const [ox, oy] of fc[String(d)] ?? []) {\n const pipeX = entity.position.x + ox;\n const pipeY = entity.position.y + oy;\n // Cap only when nothing is connected on this port.\n if (fluidPortOccupied(grid, db, pipeX, pipeY)) continue;\n\n const di = coverDirIndex(ox, oy);\n const cover = pc.covers[di];\n if (!cover) continue;\n\n const shadow = pc.shadows?.[di];\n if (shadow) {\n const sf = db.frames[shadow.frame];\n if (sf) {\n b = pushPipeCoverSprite(commands, b, entity, sf, shadow, pipeX, pipeY, sortY, sortX, 80);\n }\n }\n const cf = db.frames[cover.frame];\n if (cf) {\n b = pushPipeCoverSprite(commands, b, entity, cf, cover, pipeX, pipeY, sortY, sortX, 81);\n }\n }\n }\n return b;\n}\n","import type { Blueprint } from \"./types/blueprint.js\";\n\nexport type SnapGridRect = { x: number; y: number; w: number; h: number };\n\n/**\n * Blueprint-local axis-aligned snap rectangle from Factorio snap metadata.\n * Returns null when snap-to-grid is absent or non-positive.\n *\n * The preview box is always anchored at the blueprint origin `(0,0)` with size\n * `snap-to-grid`. `position-relative-to-grid` only affects world absolute\n * placement, not the local preview rectangle.\n */\nexport function snapGridRect(bp: Blueprint): SnapGridRect | null {\n const snap = bp[\"snap-to-grid\"];\n if (!snap || !isPositiveFinite(snap.x) || !isPositiveFinite(snap.y)) return null;\n return { x: 0, y: 0, w: snap.x, h: snap.y };\n}\n\nfunction isPositiveFinite(n: number): boolean {\n return Number.isFinite(n) && n > 0;\n}\n","import { snapGridRect } from \"../snap-grid.js\";\nimport type { Blueprint } from \"../types/blueprint.js\";\nimport {\n type DrawCmd,\n type DrawList,\n RENDER_LAYERS,\n type SnapGridCmd,\n} from \"../types/draw-list.js\";\nimport { includeCmdBounds } from \"./bounds.js\";\n\n/** Emit the green snap-to-grid rectangle when the blueprint has snap metadata. */\nexport function emitSnapGrid(\n bp: Blueprint,\n commands: DrawCmd[],\n bounds: DrawList[\"bounds\"] | null,\n): DrawList[\"bounds\"] | null {\n const rect = snapGridRect(bp);\n if (!rect) return bounds;\n\n const cmd: SnapGridCmd = {\n kind: \"snap-grid\",\n layer: RENDER_LAYERS[\"selection-box\"],\n sortY: 0,\n sortX: 0,\n entity: 0,\n sub: 0,\n x: rect.x,\n y: rect.y,\n w: rect.w,\n h: rect.h,\n };\n commands.push(cmd);\n return includeCmdBounds(bounds, cmd);\n}\n","import type { SpriteCmd } from \"../types/draw-list.js\";\nimport type { FrameMeta, TileMaterialAtlas } from \"../types/render-db.js\";\n\n/**\n * Deterministic integer hash of tile coordinates for picking among tile frame\n * variants. Stable across runs / platforms for the same (x, y).\n */\nexport function tileVariantHash(x: number, y: number): number {\n let h = (Math.imul(x | 0, 374761393) + Math.imul(y | 0, 668265263)) | 0;\n h = Math.imul(h ^ (h >>> 13), 1274126177);\n return (h ^ (h >>> 16)) >>> 0;\n}\n\n/** Positive modulo for tile grid coordinates (handles negatives). */\nexport function tileMod(n: number, m: number): number {\n return ((n % m) + m) % m;\n}\n\nfunction materialVariantOrigin(\n variantIdx: number,\n material: TileMaterialAtlas,\n): { x: number; y: number } {\n const patchPxW = material.patchW * material.tilePx;\n const patchPxH = material.patchH * material.tilePx;\n const lineLength = material.lineLength ?? 0;\n const sheetX = material.sheetX ?? 0;\n const sheetY = material.sheetY ?? 0;\n if (lineLength > 0) {\n return {\n x: sheetX + (variantIdx % lineLength) * patchPxW,\n y: sheetY + Math.floor(variantIdx / lineLength) * patchPxH,\n };\n }\n return { x: sheetX + variantIdx * patchPxW, y: sheetY };\n}\n\nexport function planMaterialTileSprite(\n tx: number,\n ty: number,\n material: TileMaterialAtlas,\n layer: number,\n frames: FrameMeta[],\n): SpriteCmd | null {\n const { patchW, patchH, tilePx, count } = material;\n const bx = Math.floor(tx / patchW) * patchW;\n const by = Math.floor(ty / patchH) * patchH;\n const frameId = material.sheet;\n const frame = frames[frameId];\n if (!frame) return null;\n const variantIdx = tileVariantHash(bx, by) % count;\n const patchOrigin = materialVariantOrigin(variantIdx, material);\n const lx = tileMod(tx, patchW);\n const ly = tileMod(ty, patchH);\n return {\n kind: \"sprite\",\n layer,\n sortY: 0,\n sortX: 0,\n entity: 0,\n sub: 0,\n frame: frameId,\n x: tx,\n y: ty,\n w: 1,\n h: 1,\n src: {\n x: patchOrigin.x + lx * tilePx,\n y: patchOrigin.y + ly * tilePx,\n w: tilePx,\n h: tilePx,\n },\n };\n}\n","import type { BlueprintEntity } from \"../types/blueprint.js\";\nimport { type DrawCmd, RENDER_LAYERS, type RectCmd } from \"../types/draw-list.js\";\nimport type { RenderDb, SpriteVariant } from \"../types/render-db.js\";\nimport { spriteDest } from \"./bounds.js\";\n\n/** Render-db icon key for the fpsr-owned unsupported mod entity marker. */\nexport const UNSUPPORTED_ENTITY_ICON_KEY = \"utility/unsupported-entity\";\n\n/** Default 1×1 footprint for entities absent from the render-db (mod content). */\nconst UNSUPPORTED_ENTITY_BOX: [[number, number], [number, number]] = [\n [-0.5, -0.5],\n [0.5, 0.5],\n];\n\n/** Orange fallback when the baked marker frame is unavailable (tests, stale db). */\nconst UNSUPPORTED_ENTITY_COLOR: [number, number, number, number] = [1, 0.55, 0, 1];\n\n/** 64px marker art at proto scale 0.5 → 1 tile on map. */\nconst UNSUPPORTED_ENTITY_MARKER_SCALE = 0.5;\n\nfunction unsupportedEntityRect(entity: BlueprintEntity): RectCmd {\n const [[x1, y1], [x2, y2]] = UNSUPPORTED_ENTITY_BOX;\n return {\n kind: \"rect\",\n layer: RENDER_LAYERS.object,\n sortY: entity.position.y + y2,\n sortX: entity.position.x,\n entity: entity.entity_number,\n sub: 0,\n x: entity.position.x + x1,\n y: entity.position.y + y1,\n w: x2 - x1,\n h: y2 - y1,\n color: UNSUPPORTED_ENTITY_COLOR,\n };\n}\n\nexport function unsupportedEntityCommand(entity: BlueprintEntity, db: RenderDb): DrawCmd {\n const frameId = db.icons[UNSUPPORTED_ENTITY_ICON_KEY];\n if (frameId != null) {\n const frame = db.frames[frameId];\n if (frame) {\n const variant: SpriteVariant = {\n frame: frameId,\n scale: UNSUPPORTED_ENTITY_MARKER_SCALE,\n shift: [0, 0],\n };\n const [, [, y2]] = UNSUPPORTED_ENTITY_BOX;\n const dest = spriteDest(entity.position.x, entity.position.y, frame, variant);\n return {\n kind: \"sprite\",\n layer: RENDER_LAYERS.object,\n sortY: entity.position.y + y2,\n sortX: entity.position.x,\n entity: entity.entity_number,\n sub: 0,\n frame: frameId,\n x: dest.x,\n y: dest.y,\n w: dest.w,\n h: dest.h,\n };\n }\n }\n return unsupportedEntityRect(entity);\n}\n","import { dir16ToIndex } from \"../resolve.js\";\nimport { buildTrainChainGeometry } from \"../train-chains.js\";\nimport type { Blueprint, BlueprintEntity } from \"../types/blueprint.js\";\nimport {\n type DrawCmd,\n type DrawList,\n RENDER_LAYERS,\n type TrainChainCmd,\n type WireCmd,\n} from \"../types/draw-list.js\";\nimport type { EntityRenderDef, WireAnchorMap } from \"../types/render-db.js\";\nimport { WIRE_CONNECTOR_ID, type WireColor, wireConnectorColor } from \"../wire-connectors.js\";\nimport { includeCmdBounds } from \"./bounds.js\";\n\nfunction isDirection4AnchorMap(anchors: WireAnchorMap): boolean {\n const keys = Object.keys(anchors);\n return keys.length > 0 && keys.every((k) => k === \"0\" || k === \"1\" || k === \"2\" || k === \"3\");\n}\n\nfunction wireAnchorDirIndex(\n direction: number | undefined,\n anchors: WireAnchorMap | undefined,\n): string {\n if (!anchors) return \"0\";\n // Prefer direction16 → direction4 (when 4-way map) → direction8 → direction4 → \"0\".\n // Poles key anchors \"0\"..\"3\"; trying direction8 first mis-maps east (4) → key \"2\".\n const d = (((direction ?? 0) % 16) + 16) % 16;\n if (anchors[String(d)]) return String(d);\n const d4 = String(Math.floor(d / 4) % 4);\n if (isDirection4AnchorMap(anchors) && anchors[d4]) return d4;\n const d8 = String(dir16ToIndex(d, \"direction8\"));\n if (anchors[d8]) return d8;\n if (anchors[d4]) return d4;\n if (anchors[\"0\"]) return \"0\";\n return Object.keys(anchors)[0] ?? \"0\";\n}\n\n/**\n * Pick wire endpoint. Combinator output connectors (3/4) and power-switch right\n * copper (6) use `data.wireAnchorsOutput` when present; otherwise `wireAnchors`.\n * Belts key anchors by circuit-connector topology (0–6); pass `beltVariation`.\n */\nfunction wireEndpoint(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n color: WireColor,\n connectorId: number,\n direction?: number,\n beltVariation?: number,\n): [number, number] {\n const useOutput =\n connectorId === WIRE_CONNECTOR_ID.combinator_output_red ||\n connectorId === WIRE_CONNECTOR_ID.combinator_output_green ||\n connectorId === WIRE_CONNECTOR_ID.power_switch_right_copper;\n const primary = useOutput ? def.data?.wireAnchorsOutput : def.data?.wireAnchors;\n const fallback = def.data?.wireAnchors;\n const anchors = primary && Object.keys(primary).length > 0 ? primary : fallback;\n const key =\n def.kind === \"belt\" && beltVariation !== undefined\n ? String(beltVariation)\n : wireAnchorDirIndex(direction ?? entity.direction, anchors);\n const set = anchors?.[key] ?? (def.kind === \"belt\" ? anchors?.[\"0\"] : undefined);\n const offset = set?.[color] ?? set?.copper ?? ([0, -0.5] as [number, number]);\n return [entity.position.x + offset[0], entity.position.y + offset[1]];\n}\n\nexport function emitWires(\n bp: Blueprint,\n byNumber: Map<number, { entity: BlueprintEntity; def: EntityRenderDef }>,\n poleDirs: Map<number, number>,\n beltVariations: Map<number, number>,\n commands: DrawCmd[],\n bounds: DrawList[\"bounds\"] | null,\n): DrawList[\"bounds\"] | null {\n const wires = bp.wires;\n if (!wires?.length) return bounds;\n let b = bounds;\n let sub = 0;\n for (const w of wires) {\n if (!Array.isArray(w) || w.length < 4) continue;\n const [srcNum, srcConn, dstNum, dstConn] = w;\n const src = byNumber.get(srcNum);\n const dst = byNumber.get(dstNum);\n if (!src || !dst) continue; // missing entity — skip gracefully\n const color = wireConnectorColor(srcConn) ?? wireConnectorColor(dstConn);\n if (!color) continue;\n const srcDir =\n src.def.protoType === \"electric-pole\" ? poleDirs.get(srcNum) : src.entity.direction;\n const dstDir =\n dst.def.protoType === \"electric-pole\" ? poleDirs.get(dstNum) : dst.entity.direction;\n const [x1, y1] = wireEndpoint(\n src.entity,\n src.def,\n color,\n srcConn,\n srcDir,\n beltVariations.get(srcNum),\n );\n const [x2, y2] = wireEndpoint(\n dst.entity,\n dst.def,\n color,\n dstConn,\n dstDir,\n beltVariations.get(dstNum),\n );\n const cmd: WireCmd = {\n kind: \"wire\",\n layer: RENDER_LAYERS.wires,\n sortY: 0,\n sortX: 0,\n entity: srcNum,\n sub: sub++,\n wire: color,\n x1,\n y1,\n x2,\n y2,\n };\n commands.push(cmd);\n b = includeCmdBounds(b, cmd);\n }\n return b;\n}\n\n/** Emit neon-green joint chain overlay for coupled rolling stock. */\nexport function emitTrainChains(\n bp: Blueprint,\n byNumber: Map<number, { entity: BlueprintEntity; def: EntityRenderDef }>,\n commands: DrawCmd[],\n bounds: DrawList[\"bounds\"] | null,\n): DrawList[\"bounds\"] | null {\n const geom = buildTrainChainGeometry(bp, byNumber);\n if (!geom) return bounds;\n const cmd: TrainChainCmd = {\n kind: \"train-chain\",\n layer: RENDER_LAYERS[\"selection-box\"],\n sortY: 0,\n sortX: 0,\n entity: 0,\n sub: 0,\n segments: geom.segments,\n joints: geom.joints,\n };\n commands.push(cmd);\n return includeCmdBounds(bounds, cmd);\n}\n","import { planAltModeCommands, planRequestPinCommands } from \"../alt-mode.js\";\nimport { emitCargoBayConnections } from \"../cargo-bay-connections.js\";\nimport { migrateTo2x } from \"../migrate.js\";\nimport { type PlanProfile, nowMs } from \"../profile.js\";\nimport {\n cardinalDirection,\n collectBeltReaderEntities,\n createResolveContext,\n resolveWithContext,\n} from \"../resolve.js\";\nimport type { Blueprint, BlueprintEntity, Color } from \"../types/blueprint.js\";\nimport {\n type DrawCmd,\n type DrawList,\n RENDER_LAYERS,\n type RectCmd,\n type SpriteCmd,\n compareDrawCmd,\n} from \"../types/draw-list.js\";\nimport type { EntityRenderDef, RenderDb, RenderLayerName } from \"../types/render-db.js\";\nimport { emitBeltReaders } from \"./belt-readers.js\";\nimport { includeCmdBounds, spriteDest, undergroundBeltUnderlayClip } from \"./bounds.js\";\nimport {\n buildBeltConnectorVariations,\n emitBeltCircuitConnectors,\n emitCircuitConnectors,\n emitCombinatorDisplay,\n} from \"./circuit-connectors.js\";\nimport { emitPipeCovers } from \"./pipe-covers.js\";\nimport { emitSnapGrid } from \"./snap-grid.js\";\nimport { planMaterialTileSprite, tileVariantHash } from \"./tiles.js\";\nimport { unsupportedEntityCommand } from \"./unsupported.js\";\nimport { emitTrainChains, emitWires } from \"./wires.js\";\n\n/** Normalize blueprint/proto color to 0–1 RGBA (Factorio may export 0–255). */\nexport function normalizeEntityColor(color: Color): [number, number, number, number] {\n let r = color.r;\n let g = color.g;\n let b = color.b;\n let a = color.a ?? 1;\n if (r > 1 || g > 1 || b > 1 || a > 1) {\n r /= 255;\n g /= 255;\n b /= 255;\n if (a > 1) a /= 255;\n }\n return [r, g, b, a];\n}\n\nfunction isRuntimeColorMaskGroup(def: EntityRenderDef, groupIndex: number): boolean {\n const maskIndex = def.data?.colorMaskGroupIndex;\n const maskIndices = def.data?.colorMaskGroupIndices;\n return (\n (typeof maskIndex === \"number\" && groupIndex === maskIndex) ||\n (Array.isArray(maskIndices) && maskIndices.includes(groupIndex))\n );\n}\n\nfunction runtimeColorMaskTint(\n entity: BlueprintEntity,\n def: EntityRenderDef,\n groupIndex: number,\n): [number, number, number, number] | undefined {\n if (!isRuntimeColorMaskGroup(def, groupIndex)) return undefined;\n const fromEntity = entity.color;\n if (fromEntity) return normalizeEntityColor(fromEntity);\n const fallback = def.data?.defaultColor;\n if (Array.isArray(fallback) && fallback.length >= 3) {\n return [\n Number(fallback[0]) || 0,\n Number(fallback[1]) || 0,\n Number(fallback[2]) || 0,\n fallback[3] == null ? 1 : Number(fallback[3]) || 0,\n ];\n }\n // Factorio locomotive default when neither blueprint nor prototype color is present.\n if (def.kind === \"train\") return [242 / 255, 0, 0, 1];\n return undefined;\n}\n\nexport interface PlanOptions {\n /** Emit blueprint-derived entity-info overlays (recipes, filters, signals, quality). */\n altMode?: boolean;\n /**\n * Emit belt starting/ending cap sprites. Default true.\n * Caps use a full-tile shift behind/ahead of the belt (FBE-aligned).\n */\n beltEndings?: boolean;\n /**\n * When true, attach phase timings on the returned {@link PlanResult.profile}.\n * Near-zero overhead when omitted/false.\n */\n profile?: boolean;\n}\n\nexport interface PlanResult {\n drawList: DrawList;\n /** Present when {@link PlanOptions.profile} was true. */\n profile?: PlanProfile;\n}\n\n/** @internal Mutable profiling sink used by the renderer hot path. */\nexport interface PlanInternalOptions extends PlanOptions {\n profileOut?: PlanProfile;\n}\n\nconst OBJECT_SORT_LAYERS: ReadonlySet<RenderLayerName> = new Set([\n \"lower-object\",\n \"lower-object-above-shadow\",\n \"lower-object-overlay\",\n \"object-under\",\n \"object\",\n \"higher-object-under\",\n \"higher-object-above\",\n \"train-stop-top\",\n \"elevated-object\",\n]);\n\ntype LegacyRailBedAxis = \"x\" | \"y\" | \"both\";\n\ninterface LegacyRailBedCandidate {\n cmd: SpriteCmd;\n axis: LegacyRailBedAxis;\n}\n\nfunction legacyRailBedAxis(protoType: string, cmd: SpriteCmd): LegacyRailBedAxis {\n if (cmd.w === cmd.h) return \"both\";\n if (protoType === \"legacy-curved-rail\") return cmd.w > cmd.h ? \"x\" : \"y\";\n return cmd.w > cmd.h ? \"y\" : \"x\";\n}\n\nfunction markLegacyRailBedSeams(candidates: LegacyRailBedCandidate[]): void {\n const epsilon = 1e-6;\n const spansJoin = (a0: number, a1: number, b0: number, b1: number) => {\n const overlap = Math.min(a1, b1) - Math.max(a0, b0);\n return overlap >= Math.min(a1 - a0, b1 - b0) - epsilon;\n };\n const allows = (candidate: LegacyRailBedCandidate, axis: \"x\" | \"y\") =>\n candidate.axis === axis || candidate.axis === \"both\";\n const mark = (cmd: SpriteCmd, edge: keyof NonNullable<SpriteCmd[\"seamBleed\"]>) => {\n cmd.seamBleed ??= {};\n cmd.seamBleed[edge] = true;\n };\n\n const top = new Map<string, LegacyRailBedCandidate[]>();\n const right = new Map<string, LegacyRailBedCandidate[]>();\n const bottom = new Map<string, LegacyRailBedCandidate[]>();\n const left = new Map<string, LegacyRailBedCandidate[]>();\n const index = (\n map: Map<string, LegacyRailBedCandidate[]>,\n edge: number,\n spanStart: number,\n spanEnd: number,\n candidate: LegacyRailBedCandidate,\n ) => {\n const edgeKey = Math.round(edge / epsilon);\n const firstCell = Math.floor(spanStart + epsilon);\n const lastCell = Math.ceil(spanEnd - epsilon);\n for (let cell = firstCell; cell < lastCell; cell++) {\n const key = `${edgeKey}:${cell}`;\n const bucket = map.get(key);\n if (bucket) bucket.push(candidate);\n else map.set(key, [candidate]);\n }\n };\n\n for (const candidate of candidates) {\n const { cmd } = candidate;\n if (allows(candidate, \"y\")) {\n index(top, cmd.y, cmd.x, cmd.x + cmd.w, candidate);\n index(bottom, cmd.y + cmd.h, cmd.x, cmd.x + cmd.w, candidate);\n }\n if (allows(candidate, \"x\")) {\n index(left, cmd.x, cmd.y, cmd.y + cmd.h, candidate);\n index(right, cmd.x + cmd.w, cmd.y, cmd.y + cmd.h, candidate);\n }\n }\n\n const connect = (\n trailing: Map<string, LegacyRailBedCandidate[]>,\n leading: Map<string, LegacyRailBedCandidate[]>,\n spanAxis: \"x\" | \"y\",\n trailingEdge: keyof NonNullable<SpriteCmd[\"seamBleed\"]>,\n leadingEdge: keyof NonNullable<SpriteCmd[\"seamBleed\"]>,\n ) => {\n for (const [key, trailingCandidates] of trailing) {\n const leadingCandidates = leading.get(key);\n if (!leadingCandidates) continue;\n for (const a of trailingCandidates) {\n for (const b of leadingCandidates) {\n if (a === b) continue;\n const overlapsSpan =\n spanAxis === \"x\"\n ? spansJoin(a.cmd.x, a.cmd.x + a.cmd.w, b.cmd.x, b.cmd.x + b.cmd.w)\n : spansJoin(a.cmd.y, a.cmd.y + a.cmd.h, b.cmd.y, b.cmd.y + b.cmd.h);\n if (!overlapsSpan) continue;\n mark(a.cmd, trailingEdge);\n mark(b.cmd, leadingEdge);\n }\n }\n }\n };\n\n connect(bottom, top, \"x\", \"bottom\", \"top\");\n connect(right, left, \"y\", \"right\", \"left\");\n}\n\nexport { undergroundBeltUnderlayClip } from \"./bounds.js\";\nexport { tileMod, tileVariantHash } from \"./tiles.js\";\nexport { UNSUPPORTED_ENTITY_ICON_KEY } from \"./unsupported.js\";\n\n/**\n * Pure draw planner: blueprint + render-db -> sorted DrawList.\n * Profiling details are available via {@link planDrawListWithOptions}.\n */\nexport function planDrawList(bp: Blueprint, db: RenderDb, opts?: PlanOptions): DrawList {\n return planDrawListWithOptions(bp, db, opts).drawList;\n}\n\n/**\n * Plan a draw list, optionally collecting phase timings when `opts.profile` is true.\n * Accepts only the public {@link PlanOptions} surface.\n */\nexport function planDrawListWithOptions(\n bp: Blueprint,\n db: RenderDb,\n opts?: PlanOptions,\n): PlanResult {\n return planDrawListInternal(bp, db, opts);\n}\n\n/**\n * @internal Renderer hot-path planner that may fill a mutable `profileOut` sink.\n * Not part of the stable `@rickyzhangca/fpsr/planner` API.\n */\nexport function planDrawListInternal(\n bp: Blueprint,\n db: RenderDb,\n opts?: PlanInternalOptions,\n): PlanResult {\n const altMode = opts?.altMode ?? true;\n const beltEndings = opts?.beltEndings ?? true;\n const profile =\n opts?.profileOut ??\n (opts?.profile\n ? {\n migrateMs: 0,\n resolveMs: 0,\n tilesMs: 0,\n entitiesMs: 0,\n overlaysMs: 0,\n sortMs: 0,\n totalMs: 0,\n }\n : undefined);\n const tTotal = profile ? nowMs() : 0;\n\n let t = profile ? nowMs() : 0;\n bp = migrateTo2x(bp);\n if (profile) profile.migrateMs = nowMs() - t;\n\n const commands: DrawCmd[] = [];\n let bounds: DrawList[\"bounds\"] | null = null;\n\n // --- tiles ---\n t = profile ? nowMs() : 0;\n for (const tile of bp.tiles ?? []) {\n const def = db.tiles[tile.name];\n if (!def) continue;\n const layer = RENDER_LAYERS[def.layer];\n const tx = tile.position.x;\n const ty = tile.position.y;\n\n if (def.material && def.material.count > 0) {\n const cmd = planMaterialTileSprite(tx, ty, def.material, layer, db.frames);\n if (!cmd) continue;\n commands.push(cmd);\n bounds = includeCmdBounds(bounds, cmd, db.frames);\n } else if (def.frames && def.frames.length > 0) {\n const frameId = def.frames[tileVariantHash(tx, ty) % def.frames.length];\n if (frameId === undefined) continue;\n const frame = db.frames[frameId];\n if (!frame) continue;\n const cmd: SpriteCmd = {\n kind: \"sprite\",\n layer,\n sortY: 0,\n sortX: 0,\n entity: 0,\n sub: 0,\n frame: frameId,\n x: tx,\n y: ty,\n w: 1,\n h: 1,\n };\n commands.push(cmd);\n bounds = includeCmdBounds(bounds, cmd, db.frames);\n } else {\n const cmd: RectCmd = {\n kind: \"rect\",\n layer,\n sortY: 0,\n sortX: 0,\n entity: 0,\n sub: 0,\n x: tx,\n y: ty,\n w: 1,\n h: 1,\n color: def.color,\n };\n commands.push(cmd);\n bounds = includeCmdBounds(bounds, cmd);\n }\n }\n if (profile) profile.tilesMs = nowMs() - t;\n\n // --- entities ---\n t = profile ? nowMs() : 0;\n for (const entity of bp.entities ?? []) {\n if (db.entities[entity.name]) continue;\n const cmd = unsupportedEntityCommand(entity, db);\n commands.push(cmd);\n bounds = includeCmdBounds(bounds, cmd, db.frames);\n }\n\n const tResolve = profile ? nowMs() : 0;\n const resolveContext = createResolveContext(bp, db);\n const resolved = resolveWithContext(resolveContext, undefined, { beltEndings });\n if (profile) profile.resolveMs = nowMs() - tResolve;\n\n const byNumber = new Map<number, { entity: BlueprintEntity; def: EntityRenderDef }>();\n const legacyRailBeds: LegacyRailBedCandidate[] = [];\n for (const { entity, def, selections } of resolved) {\n byNumber.set(entity.entity_number, { entity, def });\n // Rolling stock collision boxes are elongated along the track; using the\n // south edge makes a horizontal loco sort past trackside entities (e.g. a\n // train-stop to the south). Factorio sorts rolling stock by position.y.\n const sortYObject =\n def.kind === \"train\" ? entity.position.y : entity.position.y + def.collisionBox[1][1];\n const sortXObject = entity.position.x;\n\n for (const sel of selections) {\n const group = def.graphics[sel.group];\n if (!group) continue;\n // A zero runtime color is Factorio's sentinel for an unpainted vehicle;\n // do not draw its apply_runtime_tint mask until the blueprint/prototype\n // supplies an actual color.\n if (\n def.kind === \"vehicle\" &&\n isRuntimeColorMaskGroup(def, sel.group) &&\n !entity.color &&\n !Array.isArray(def.data?.defaultColor)\n ) {\n continue;\n }\n const variants = group.variants[sel.variantKey] ?? group.variants.default;\n if (!variants) continue;\n const variant = variants[sel.index];\n if (!variant) continue;\n\n const frame = db.frames[variant.frame];\n if (!frame) continue;\n\n const dest = spriteDest(entity.position.x, entity.position.y, frame, variant, sel.shift);\n // Legacy render-dbs distilled splitter structure_patch as object-under.\n // That always paints under UG hoods on `object`, so a hood north of an\n // E/W splitter covers its top patch. Promote to `object` (sub keeps patch\n // under the same entity's structure).\n const layerName: RenderLayerName =\n def.kind === \"splitter\" && group.layer === \"object-under\" ? \"object\" : group.layer;\n const isObjectLayer = OBJECT_SORT_LAYERS.has(layerName);\n const cmd: SpriteCmd = {\n kind: \"sprite\",\n layer: RENDER_LAYERS[layerName],\n sortY: isObjectLayer ? sortYObject : 0,\n sortX: isObjectLayer ? sortXObject : 0,\n entity: entity.entity_number,\n sub: sel.group,\n frame: variant.frame,\n x: dest.x,\n y: dest.y,\n w: dest.w,\n h: dest.h,\n };\n if (variant.tint) cmd.tint = variant.tint;\n const maskTint = runtimeColorMaskTint(entity, def, sel.group);\n if (maskTint) cmd.tint = maskTint;\n if (variant.drawAsShadow) cmd.shadow = true;\n if (variant.flipX) cmd.flipX = true;\n if (variant.flipY) cmd.flipY = true;\n if (variant.rotation != null && variant.rotation !== 0) cmd.rotation = variant.rotation;\n if (\n (def.protoType === \"legacy-straight-rail\" || def.protoType === \"legacy-curved-rail\") &&\n layerName === \"rail-stone-path-lower\"\n ) {\n legacyRailBeds.push({ cmd, axis: legacyRailBedAxis(def.protoType, cmd) });\n }\n\n // UG/loader belt underlay: clip straight to open-side half (caps stay full).\n if (\n (def.kind === \"underground-belt\" || def.kind === \"loader\") &&\n group.layer === \"transport-belt\" &&\n sel.variantKey !== \"start\" &&\n sel.variantKey !== \"end\"\n ) {\n const facing = cardinalDirection(entity.direction ?? 0);\n const openDir = entity.type === \"output\" ? facing : (((facing + 8) % 16) as 0 | 4 | 8 | 12);\n cmd.clip = undergroundBeltUnderlayClip(dest, openDir);\n }\n commands.push(cmd);\n bounds = includeCmdBounds(bounds, cmd, db.frames);\n }\n\n bounds = emitCombinatorDisplay(entity, def, db, commands, bounds);\n\n // Request pins are always shown; alt mode only adds entity-info overlays.\n const requestPins = planRequestPinCommands(entity, def, db);\n for (const cmd of requestPins) {\n commands.push(cmd);\n bounds = includeCmdBounds(bounds, cmd, db.frames);\n }\n if (altMode) {\n for (const cmd of planAltModeCommands(entity, def, db, {\n insertCommands: requestPins,\n })) {\n commands.push(cmd);\n bounds = includeCmdBounds(bounds, cmd, db.frames);\n }\n }\n }\n markLegacyRailBedSeams(legacyRailBeds);\n if (profile) {\n // Exclude resolve from entitiesMs so phases are additive.\n profile.entitiesMs = nowMs() - t - profile.resolveMs;\n }\n\n t = profile ? nowMs() : 0;\n const { beltIndex, poleDirs } = resolveContext;\n const beltVariations = buildBeltConnectorVariations(bp, byNumber, beltIndex);\n const readerEntities = collectBeltReaderEntities(bp, db, beltIndex);\n bounds = emitCircuitConnectors(bp, db, byNumber, poleDirs, commands, bounds);\n bounds = emitBeltReaders(bp, db, byNumber, beltIndex, readerEntities, commands, bounds);\n bounds = emitBeltCircuitConnectors(bp, db, byNumber, beltVariations, commands, bounds);\n bounds = emitPipeCovers(bp, db, byNumber, commands, bounds);\n bounds = emitWires(bp, byNumber, poleDirs, beltVariations, commands, bounds);\n bounds = emitTrainChains(bp, byNumber, commands, bounds);\n bounds = emitSnapGrid(bp, commands, bounds);\n const commandsBeforeConnections = commands.length;\n emitCargoBayConnections(bp, db, resolveContext.preferPlatformGraphics, commands);\n for (let i = commandsBeforeConnections; i < commands.length; i++) {\n const cmd = commands[i];\n if (cmd) bounds = includeCmdBounds(bounds, cmd, db.frames);\n }\n if (profile) profile.overlaysMs = nowMs() - t;\n\n t = profile ? nowMs() : 0;\n commands.sort(compareDrawCmd);\n if (profile) {\n profile.sortMs = nowMs() - t;\n profile.totalMs = nowMs() - tTotal;\n }\n\n if (commands.length === 0) {\n return {\n drawList: {\n schema: 1,\n bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 },\n commands: [],\n },\n profile,\n };\n }\n\n return {\n drawList: {\n schema: 1,\n bounds: bounds ?? { minX: 0, minY: 0, maxX: 0, maxY: 0 },\n commands,\n },\n profile,\n };\n}\n","import { includeCmdBounds } from \"./plan/bounds.js\";\nimport type { DrawCmd, DrawList, DrawListBounds, RectCmd } from \"./types/draw-list.js\";\nimport type { FrameMeta } from \"./types/render-db.js\";\n\nfunction intersects(left: DrawListBounds, right: DrawListBounds, bleed: number): boolean {\n return (\n left.maxX + bleed >= right.minX &&\n left.minX - bleed <= right.maxX &&\n left.maxY + bleed >= right.minY &&\n left.minY - bleed <= right.maxY\n );\n}\n\nconst separator = (frame: DrawListBounds): RectCmd => ({\n kind: \"rect\",\n layer: 0,\n sortY: 0,\n sortX: 0,\n entity: 0,\n sub: 0,\n x: frame.minX,\n y: frame.minY,\n w: 0,\n h: 0,\n color: [0, 0, 0, 0],\n});\n\n/**\n * Retain commands that can affect one viewport while preserving shadow-run\n * boundaries. The transparent separators prevent independently composited\n * shadow runs from becoming adjacent after culling.\n */\nexport function drawListForTile(\n list: DrawList,\n frames: FrameMeta[],\n frame: DrawListBounds,\n bleedTiles = 0.25,\n): DrawList {\n const commands: DrawCmd[] = [];\n let sourceShadowRun = 0;\n let sourceWasShadow = false;\n let lastIncludedShadowRun: number | undefined;\n\n for (const command of list.commands) {\n const isShadow = command.kind === \"sprite\" && command.shadow === true;\n if (isShadow && !sourceWasShadow) sourceShadowRun++;\n sourceWasShadow = isShadow;\n const bounds = includeCmdBounds(null, command, frames);\n if (!intersects(bounds, frame, bleedTiles)) continue;\n\n if (\n isShadow &&\n lastIncludedShadowRun != null &&\n lastIncludedShadowRun !== sourceShadowRun &&\n commands.at(-1)?.kind === \"sprite\" &&\n (commands.at(-1) as Extract<DrawCmd, { kind: \"sprite\" }>).shadow === true\n ) {\n commands.push(separator(frame));\n }\n commands.push(command);\n lastIncludedShadowRun = isShadow ? sourceShadowRun : undefined;\n }\n\n return { ...list, commands };\n}\n"],"mappings":"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"}
|