Laundromat

by Slothic

Every ore patch is a currency. Mine dirty cash, wash it, strap it, seal it into vacuum bricks, and move it across five jurisdictions. Burn the small notes for power; ship the large ones.

Overhaul
2 months ago
2.1
30

Changelog

Version: 0.10.0
Date: 2026-08-30
  Major Features:
    - WATER POLLUTION. Washing dirties the lake the Washer stands beside.
      There is deliberately no polluted-water fluid and no dirty output
      pipe: a fluid can be tanked, barrelled or simply left unconnected,
      and any of those turns the consequence into paperwork. The Washer
      poisons water by running. The only choice is which medium takes it
      -- water if any is in reach, air if not.
    - Both the Washer and the Treatment Plant are shoreline-only. They
      work ON the water they stand beside, so they have to stand beside
      water. Enforced on build; the machine is handed back, never eaten.
    - Air pollution over a body of water sinks into it. Burning notes for
      power dirties the air, the air dirties the lake, and a lake below
      the washing threshold cannot wash anything. This is what makes
      treatment necessary in the first hour rather than a late luxury.
    - Pollution spreads between neighbouring tiles and is CONSERVED
      exactly. A tile at 90% polluted hands 1% to a cleaner neighbour and
      is left at 89%. Nothing is destroyed. A concentrated dead spot thins
      into a broad shallow one, and the total never falls on its own.
    - THE WASHING THRESHOLD. At or above 95% clean a tile yields ordinary
      water. Below it the tile yields NOTHING -- `fluid` is nil, the
      ordinary state of every non-water tile in the game -- so an offshore
      pump there simply has nothing to draw and the wash line starves.
      This costs nothing at runtime: no script checks anything.
    - The Treatment Plant. Draws straight from the fouled water it stands
      on with no input pipe at all, and yields clean water you can pipe to
      a Washer. Every third craft lifts one lake tile a step back up.
      Since pollution is conserved everywhere else, this machine is the
      single place water pollution can leave the water -- and it leaves
      into the air, where the Scrubber and its finite wood are the only
      remaining sink.
  Features:
    - Unstrap, unwrap and unbrick. Every packaging step now runs
      backwards. This is NOT a hole in the no-breaking rule: that rule
      forbids turning a 500 into five 100s, and unpacking returns notes of
      the SAME denomination it swallowed. The vacuum brick's film does not
      come back, which is what stops brick -> unbrick -> brick being a
      free loop, and is also just true. Every reverse recipe sets
      allow_productivity = false: a productivity bonus on an unpack recipe
      returns more notes than went in, which in this mod is a printer.
    - DYE FUEL. Stripping a dye pack off marked cash leaves the dye, and
      dye is a petrochemical, so it burns. Every inked wash now yields 2
      dye residue.
    - Dye cake, and this mod's Kovarex. 40 dye residue plus solvent
      returns 41 and 8 cake. What makes vanilla's uranium loop work is not
      that it is net positive, it is that it demands a stockpile up front
      before it pays anything back. It runs in the Note Press, not the
      Scrubber -- the Scrubber emits MINUS 25/min, so concentrating fuel
      in it would have cleaned the air as a side effect of making it.
    - The dye loop does not break "the factory launders itself". It
      changes what the fuel is paid in. It eats solvent, solvent is made
      from water, and dye cake burns at four times a banknote's emissions
      -- which lands in the air, falls into the lakes, and drops them
      under the washing threshold. The loop poisons its own feedstock.
    - The Scrubber has a bare "scrub-air" recipe that takes nothing and
      yields nothing. Its -25/min lives on the energy source and is
      emitted while it WORKS, so the recipe only has to occupy it.
      Previously the sole way to scrub air was to also want detergent or
      solvent: a player whose air was the problem had to overproduce
      chemicals to fix it.
    - The Hamster Wheel. One steam engine's worth of power, 900kW, for no
      fuel, forever. It costs coins like everything else. gui_mode is
      "none" on purpose -- an electric-energy-interface otherwise opens a
      panel letting the player type in their own production figure.
  Graphics:
    - EVERY MACHINE REBUILT. Seven of them shared a pre-0.8.0 pass that
      measured, against vanilla, as solid rectangles: bounding-box fill
      0.945-0.953 where vanilla runs 0.675-0.891, diagonal share of
      boundary 0.082-0.089 against 0.221-0.321, and p10 luminance
      0.14-0.16 against 0.033-0.070 -- which is to say they contained no
      genuinely dark pixels at all. Nothing was in shadow and nothing was
      a hole. At game scale they read as one flat box with a different
      coloured panel on each.
    - The Washer is now an open circular clarifier: concrete basin,
      serrated weir crest spilling into a peripheral launder, a radial
      scraper bridge making exactly one revolution per loop, flocculation
      well, handrails and a caged ladder. It is also the mod's first
      DIRECTIONAL machine, rendered in four orientations. Rotatability
      comes from the fluid boxes rather than the art, which is why
      fluid_boxes_off_when_no_fluid_recipe had to be forced false.
    - The Treatment Plant draws its own mechanic: a duct runs from the
      aeration basin's water surface into a vessel and out of a flue,
      which is exactly what the entity does to pollution.
    - The Hamster Wheel is built entirely from primitives, no model at
      all. A scanned rim would have fixed the drum depth at 0.37 of its
      diameter, and at that depth the front and back hoops project half a
      tile apart and read as two separate rings.
    - Sorter, Shredder, Strapper, Scrubber, UV Scanner, Paperwork Office
      and Requisition Terminal all rebuilt with their own models and
      silhouettes. No two machines share an identity-defining model.
    - Every model is Poly Haven CC0 except device64 and device81, which
      are licensed royalty-free. Only rendered PNGs ship; package.py
      builds from an allowlist that cannot reach gen/. Every model on
      disk is now listed in fetch_models.py, so a fresh clone reproduces
      the exact asset set -- a referenced-but-missing model is the worst
      kind of absent, because kit.model() returns empty and every builder
      falls back to primitives silently.
  Bugfixes:
    - gen/render/parts.py was missing NP_HIT, NP_SPINS, NP_SPLIT,
      NP_DEBUG_LIFT and NP_DEBUG_MARK. All five were read and none was
      ever assigned, so note_press() raised NameError and job-final -- or
      anything naming note-press -- died before rendering a pixel. The
      shipped art was fine, which is why nothing noticed. Three were
      recovered from splitprobe.py's restore block; the other two were
      MEASURED off the 64 surviving raw frames, which were rendered while
      the real values were still present. Verified by re-rendering frames
      0, 27 and 40 and diffing against those originals: head height
      matches exactly at 0 and 40.
    - The Dryer's fan rotated off its own axis. The spin pivot was the
      whole drum's bounding-box centre, and device81's feet and base plate
      pull that 0.021 tiles below the barrel -- so the cap orbited as well
      as turned, opening a crescent gap at the seam where it was cut off
      the body. kit.spin_axis() derives the pivot from the cap's own
      vertices instead. It reads vertices rather than bound_box because
      after split_meshes() bakes a transform the cached bound_box still
      reports the source asset's raw units.
    - gen/gen_chain.py carried a second EXTRACT table, referenced by
      nothing and disagreeing with the real one -- it said inked was 13%
      of extraction where the live table says 6%. Editing it to rebalance
      contamination would have changed nothing, silently. Removed, with a
      pointer to gen/gen_world.py in its place.
  Modding:
    - Tile budget measured rather than assumed: 100 steps puts the game at
      253 tile prototypes and 200 at 353, both of which load clean, so the
      255 ceiling that applied in older versions does not bite in 2.1.
    - Vanilla water carries autoplace = water_base(0, 100) and
      table.deepcopy inherits it. Left in, every toxic step would have
      competed to place itself and the map would have generated as sludge.
Version: 0.9.0
Date: 2026-08-30
  Features:
    - Water can be poisoned. A hundred water tiles run from clean to dead,
      so a lake taking wash effluent discolours continuously instead of
      flipping between two states. They cost no art at all: Factorio draws
      water with the `effect = "water"` shader, which blends between
      effect_color and effect_color_secondary, and the PNGs underneath
      carry noise and normals rather than hue. Vanilla proves it -- the
      water-green tile IS water with effect_color set to water's own
      effect_color_secondary. All hundred point at base's water{1,2,4}.png
      and land in the sprite atlas once. Authoring real sheets would have
      been 100 x 750 KB.
    - No transition sprites either. transition_merges_with_tile = "water"
      puts every step in water's transition group, so the hundred border
      each other and the shoreline with nothing drawn, which is the same
      trick vanilla uses to make water-green cheap.
    - Dead water stops absorbing air pollution. absorptions_per_second
      scales down across the gradient, so poisoning a lake makes the AIR
      worse as well. The water and air systems couple to each other in
      data, with nothing running at runtime to do it.
  Graphics:
    - The mod has a thumbnail: the DKK 50 note, cropped to the bill and
      scaled 4x with NEAREST so it stays crisp. Placeholder for now.
    - thumbnail.png added to package.py's allowlist. It is referenced by
      no Lua, so check_files.py cannot see it, and off the list it would
      have silently never shipped and the portal would show a blank tile.
  Modding:
    - Tile budget measured rather than assumed. 100 steps puts the game at
      253 tile prototypes and 200 puts it at 353; both load clean, so the
      255 ceiling that applied in older versions does not bite in 2.1.
      Deepwater is affordable whenever it is wanted.
    - Vanilla water carries autoplace = water_base(0, 100), and
      table.deepcopy inherits it. Left in, all hundred tiles would have
      competed to place themselves and every map would have generated as
      sludge. gen_world.py strips it and the data dump is checked for it.
Version: 0.8.0
Date: 2026-08-28
  Balance & UI:
    - Currency deposits are FINITE. You mine a patch out and it is gone.
      They were infinite with a permanent 12,000-per-tile floor, so an
      outpost never actually ran dry and there was no reason to expand.
      The infinite setup also needed a flat additional_richness of 60,000
      to make drills report a sane rate, which parked every tile
      permanently on the richest of the eight depletion sprites -- a patch
      never visibly wore down either. Richness is now 4,000, in the range
      a vanilla ore tile holds, so the deposits deplete through the same
      eight stages an iron patch does.
    - Hand-written locale moved to locale/en/manual.cfg. laundromat.cfg is
      regenerated by gen/gen_world.py, which had already silently
      destroyed a set of recipe names and shop tab names added to it by
      hand. Factorio merges every .cfg in the directory, so the split
      costs nothing and gen/check_locale.py reads all of them.
    - Removed ten machines from the shop that could not do anything. The
      purge disables every recipe in their crafting categories, so a
      chemical plant (18 coins), oil refinery (51), foundry (971),
      cryogenic plant, centrifuge, electromagnetic plant, crusher,
      recycler, biochamber and electric furnace could all be bought,
      placed and powered, and would sit there forever with an empty
      recipe list. 2755 coins of purchases that did nothing. The rocket
      silo has no live recipes either but is driven from control.lua, so
      it stays.
    - gen/check_shop.py refuses to let that happen again: it reads the
      post-purge data dump and fails if anything sellable has zero live
      recipes. It also fails if it finds nothing to check, rather than
      reporting a pass.
    - The accumulator was the one item in the shop that could never be
      bought. BANNED marks a few entries false on purpose -- accumulator
      among them, since storage is fine and only generation is banned --
      but the loop enforcing it used `pairs` and ignored the VALUE, so it
      disabled and hid every key regardless. Nothing unlocked it, so no
      route to it existed.
    - The shop is split into tabs by what things do -- Conveyance,
      Plumbing, Power, Rail, Production, Facilities, Sundries -- instead
      of being subgrouped by price band, which had put 77 of its 122
      entries into a single undifferentiated wall of icons.
    - The Scrubber can make solvent again. It had only an INPUT fluid
      box, and scrub-solvent produces a fluid, so the machine refused its
      own recipe with the crafting categories matching perfectly and
      nothing wrong in the log. It is the only machine here that assigns
      fluid_boxes explicitly, and it is a copy of assembling-machine-1,
      which has none to inherit.
    - The Scrubber has pipe graphics. Its fluid boxes took their art from
      `assembler2pipepictures` and `pipecoverspictures`, neither of which
      is defined anywhere in this mod -- both evaluated to nil, so pipes
      appeared to end in mid-air against a blank wall.
    - Added the missing recipe names. scrub-solvent showed in-game as
      "Unknown key: recipe-name.scrub-solvent"; Factorio only auto-names
      a recipe after its product when the two names match.
      gen/check_locale.py now checks every prototype has a name.

  Graphics:
    - Fixed the world lighting. The render's environment gradient was
      built as a SPHERICAL gradient driven by a unit-length direction
      vector, whose length is 1 in every direction - so it evaluated to a
      constant and the colour ramp always returned its first stop. There
      was no sky in any render this mod has ever shipped, only a flat dark
      brown. Metal has almost no colour of its own; it is an image of its
      surroundings, so every pipe, gear and chain in the set was
      faithfully reflecting a dark brown room and came out near black.
      The world is now a real ground-to-zenith gradient, verified by
      rendering a mirror ball and measuring that its zenith is brighter
      and cooler than its horizon.
    - Fixed the bright metals. "bare", "light" and "brass" - the three
      materials whose entire job is catching a highlight - were all built
      on a dark blue painted-plate scan measuring 0.23 luminance, under a
      tint that can only ever multiply, so they could not come out
      brighter than the scan. They now use a galvanised steel scan at 0.34
      luminance and 0.09 saturation: bright, and neutral enough to tint.
    - Machine renders are supersampled 3x and reduced with a sharp kernel,
      which is how the base game's own art is made. Measured as per-pixel
      gradient energy, rendering straight to final size scored 0.033
      against vanilla's 0.059-0.088 and would not move for texture scale,
      roughness, metallic or the denoiser; rendered large and reduced, the
      same geometry scores 0.075.
    - Added a tight second sun carrying the speculars. A sun's highlight
      is an image of its disc, so the old 11-degree key physically could
      not throw a bright glint: the sprites put 0.22% of their pixels
      above 0.75 luminance where vanilla machines put 1.9-3.7%. Now 2.8%.
    - Grading with soft roll-offs at BOTH ends. The contrast curve alone
      crushed everything below 0.09 to pure black, which is what turned
      the gears and chains into flat cut-outs.
    - Machines are now kitbashed from CC0 scanned models rather than built
      entirely from boxes and cylinders. Poly Haven publishes 521 models
      under CC0 1.0 at real-world scale, and a Factorio tile is about a
      metre, so a 0.6 x 1.7 x 1.2 m compressor sits on a 3x3 deck with no
      fudging. They are used only inside Blender; what ships is the render.
      Greeble-scale detail was 0.077 against vanilla's 0.085-0.111 and
      would not improve by adding more primitives - that density is what a
      real modelled compressor or pipe cluster has for free. It now
      measures 0.082, with fine detail at 0.081 against 0.059-0.088.
    - Imported props are toned, not bleached. A hard desaturation put the
      whole set back into one muddy family; the per-part colour variety
      scanned props bring is a large part of why vanilla machines look
      alive. What actually needed fixing was the LEVEL - imported props
      put 8.6% of their pixels above 0.75 luminance against vanilla's
      1.9-3.7%, now 3.4%.
    - Every prop falls back to a generated primitive when its model is
      missing, so the mod still builds from a fresh clone with no
      downloads. kit.model() imports .gltf/.glb/.blend/.obj/.fbx/.dae/.stl,
      so a model obtained by hand works by being dropped into
      gen/render/models/<name>/ with no code change.
    - The Note Press is now built on a scanned industrial device rather
      than on primitives. Four hand-built designs were rejected before
      this, and the common thread was density: arranging boxes and
      cylinders by hand does not reach the greeble count of real
      industrial art, and no amount of lighting or palette work covers
      for that. The model is royalty-free and used only inside Blender --
      only the rendered PNG ships.
    - Its head drops, spins and returns; the bore glows hot on the way
      down and dumps that heat into the body and the pipe runs on impact.
      The device is a single 12k-face mesh, so the head does not exist as
      a separate object until it is cut out of the geometry by face
      height at render time.
    - Steam now vents from six points -- the back radiator and both
      heated pipe runs -- every 60 ticks rather than 180. At three
      seconds apart it read as puff-pause-puff instead of the continuous
      drift a steam engine has.
    - scene.py refuses to render if any module defines the same function
      twice. A rebuilt note_press was spliced in above two stale copies
      of itself; Python takes the last definition, so the new build was
      dead code and a full render silently produced the old art.
    - Model imports are anchored AFTER rotation, not before. Fine at zero
      degrees and wrong at every other angle: stood on end, the device
      sat half underground and off-centre.
    - Rebuilt the Note Press silhouette. Measured against vanilla it was
      the wrong SHAPE, not the wrong colour: 87% of its bounding box was
      solid against vanilla's 68-77%, its skyline varied by 0.078 against
      0.10-0.14, and its outline was only 11% diagonal against 24-40%. A
      Factorio machine is an assemblage of vessels and pipework with an
      irregular skyline, not a cabinet. It now has a domed accumulator, an
      exhaust stack over the radiator it actually vents from, corner
      columns, outboard flywheels whose rims break the side outline, and
      hard plumbing routed along the back: 72% fill, 0.126 skyline.
Version: 0.7.4
Date: 2026-08-28
  Changes:
    - The block glows from the CENTRE out. A hot core over the point of
      impact falling off through four bands to the block's cooler edges,
      instead of one flat temperature across the whole face - heated steel
      is brightest where it was struck and cooler where the mass carries
      the heat away. The orange is more saturated with it.
    - The chains hook to the block's CORNERS, two a side, and go slack the
      instant it lands before taking up as the gears wind in. That moment
      of slack is the whole "oomph" of a guillotine: a chain that stays
      straight through the strike makes the block look lowered rather than
      dropped.
    - The chains wrap around the pulley rims rather than meeting them as
      straight lines, with a counterweight hanging on each slack tail.
    - Bolts on the pulley faces, turning with the wheel. A smooth disc
      gives no clue which way it is going; three bolts do it at a glance.
    - The heat pipes sit warm all the time and take a real kick when the
      block lands and the heat reaches them, rather than following the
      strike cycle exactly or ignoring it.
    - Steam vents from the radiator at the BACK of the machine, which is
      where it dumps its heat, rather than from the flanks.
  Bugfixes:
    - The centre-out glow was being drawn on the block's underside - the
      strike face - which a top-down camera never sees. It rendered
      perfectly and was hidden by the block sitting on it. It is on the
      top face now.
    - Four chain runs, an arc and a counterweight at full link size piled
      into an unreadable black mass over each wheel. Links thinned and the
      wrap shortened.
Version: 0.7.3
Date: 2026-08-28
  Changes:
    - Rust is the body colour, not an accent. The green scan was carrying
      the whole machine and read as painted plastic; vanilla's silo is
      warm brown-grey steel that has stood outside for years, with olive
      surviving on one or two components only. Measured against the
      assembler the press now sits at 0.357 saturation against 0.358, and
      at hue 54 degrees against the silo's 54.5.
    - Rust runs DOWN from the fasteners. Every bolt row on the housing,
      the well rim and the posts now streaks below itself at varied
      lengths - which is where rust actually starts on a real machine, and
      it buys more age than any amount of noise on the flat panels.
    - Bare metal, brass and copper are properly shiny. Their roughness is
      scaled well down so they take a hard specular the way the pipe tops
      do in the reference, instead of going matte.
    - The heat pipes glow constantly at working temperature rather than
      following the strike cycle, with a slow breath over the top.
  Bugfixes:
    - THE SPRITE DID NOT FIT ITS PLACEMENT BOX. The machine was 2.5 tiles
      tall on a 3x3 footprint and only 2.62 tiles deep, so its mass sat
      above its own tiles and its front edge never reached the front of
      them: pack.py computed a shift of -0.60 against the vanilla
      assembler's -0.09. Every height above the pad is scaled to 0.60 and
      the footprint is square now. The sprite's bottom edge lands at
      +1.00 tiles, and a 3x3 footprint at a 47 degree camera projects to
      exactly +/-1.02.
    - A tint CANNOT desaturate - it multiplies, so it only ever darkens.
      Pulling the tints toward neutral moved measured saturation from
      0.507 to 0.487 and no further while the scan underneath stayed
      vividly orange. tex_mat takes a real desaturation now, through a
      Hue/Saturation node.
    - The heat pipes were emitting hard enough to ring the whole machine
      in bright orange and had become the loudest thing on it. Hot metal
      at working temperature barely glows in daylight.
Version: 0.7.2
Date: 2026-08-28
  Changes:
    - The Note Press is an enclosed HOUSING now, not an open frame. It
      never sat right beside vanilla machines however it was textured, and
      the reason was structural rather than cosmetic: a Factorio machine
      is a solid chassis that fills its tiles with machinery poking up out
      of an open top - the assembler is a sealed box you look INTO to see
      its gears. An open frame you look THROUGH is scaffolding. Measured,
      the old one was 73.6% solid against the assembler's 82.4%; the new
      one is 91.3%.
      The guillotine now runs in a well sunk into the top face: you look
      down into the machine and watch the block land, while the posts,
      gears and chains stand proud of the housing.
    - No more baked steam. It is only the real turbine-smoke entity now,
      spawned at the side grilles, so it drifts on the wind like a steam
      engine's. There was never anything to trade off: script cannot read
      the animation frame, so a painted plume could not be guaranteed to
      land with the block anyway.
  Bugfixes:
    - The block dropped BELOW the well rim and disappeared for a third of
      the loop - the one thing the machine is named for, invisible. It
      comes to rest just proud of the rim now.
Version: 0.7.1
Date: 2026-08-28
  Changes:
    - Machine surfaces are scanned PBR maps instead of procedural noise.
      Noise took them from "smooth plastic" to "dented plastic"; real
      photogrammetry gives chipped paint with bare metal showing through,
      rust that has run and pooled, and scratches with direction. Against
      the vanilla assembler the Note Press moved from 0.284 saturation to
      0.406 (vanilla 0.356).
      The maps are CC0 from Poly Haven and are used only inside Blender -
      what ships here is the rendered PNG, this project's own output. See
      gen/render/tex/SOURCES.txt and fetch_tex.py.
    - The Note Press is 8 frames while its look is still being settled,
      still a 3 second stroke (animation_speed 8/180). Frame count and
      speed have to move together or the stroke stops being 3 seconds.
  Bugfixes:
    - Textures are projected from world POSITION through a box projection
      rather than from UVs. Blender primitives carry whatever UVs they are
      born with and those stretch the moment an object is scaled, so a box
      and a cylinder would have shown visibly different texel densities.
    - A tint MULTIPLIES the scan, so it darkens as well as colours. The
      first pass tinted a mid-green scan with mid-green values and landed
      at median luminance 35 against vanilla's 51 - too dark and doubly
      green.
    - scene.reset() calls read_factory_settings(use_empty=True), which
      drops every datablock including loaded images, so the texture cache
      handed out dangling references from frame two and Blender raised
      "StructRNA of type Image has been removed". The cache heals itself
      now.
    - The loop check no longer demands byte equality. A denoiser is not
      bit-deterministic: frame N and frame 0 differed by a single 1/255 on
      four pixels out of 168,100, which is not the animation failing to
      close. It now allows 2 levels on 0.1% of pixels, which still catches
      anything real - a phase that does not wrap moves geometry, and that
      moves thousands of pixels by tens of levels.
Version: 0.7.0
Date: 2026-08-28
  Features:
    - The Note Press is a GUILLOTINE. A weighted block runs between two
      outward-leaning posts with a gear at the head of each, falls onto
      the bed under its own weight, flashes red hot and vents steam from
      both sides, and is then hauled back up on two chains while it cools.
      64 frames over three seconds.
      The fall is squared time, not eased: a guillotine accelerates into
      the impact rather than settling onto it like a hydraulic ram. The
      gears turn as a function of block HEIGHT, so their phase is
      periodic without having to be made so.
    - Copper heat pipes ring the bed and glow with the heat on a phase
      lag, dumping into a finned radiator at the back. The lag is modular,
      so the first and last frames still evaluate identically.
    - Real steam. turbine-smoke - the steam-turbine plume - is spawned
      from control.lua at both vents while the press is working, so it
      drifts with the wind exactly as a steam engine's does. Sprite steam
      cannot do that; it is painted in place.
      The sharp burst at the moment of impact stays baked into the
      animation, because it has to land on the exact frame the block
      strikes and script cannot know the animation frame - Factorio
      advances graphics_set.animation at its own rate and does not expose
      it. So the burst is frame-exact and the drifting cloud is real.
  Changes:
    - animation_speed is per-machine now. Frames and speed have to move
      together: 64 frames at the old 0.5 would be a 2.1 second stroke,
      not 3. The press runs at 64/180 = 0.35556.
    - Glow is red hot, not white hot. The first pass emitted at strength
      3.2 and clipped through orange into yellow-white, which reads as a
      lamp rather than as heated steel. It is on a heat^1.6 curve now, so
      the peak is brief and the cool-down long.
Version: 0.6.9
Date: 2026-08-28
  Features:
    - "Test run (animation)": a recipe in the Note Press that takes
      nothing and makes nothing, so the machine runs forever without
      stalling. A crafting machine only advances its animation while it
      is actually crafting, so watching one move otherwise means feeding
      it real inputs and clearing its output before it blocks. It is
      deliberately worthless - any output at all would make it a free
      source of that item.
  Changes:
    - Note Press again: surface relief, tubular masses and a warmer
      palette. The noise now drives the surface NORMAL as well as colour
      and roughness, so every panel carries coarse dents with fine
      scratches over them - previously every face was a smooth gradient,
      which was much of the plastic look. The side housings are banded
      drums rather than slabs, the frame is laced with pipe runs that
      have bolted flanges at their joints, and those runs change material
      along their length and are clamped at intervals instead of being
      one extruded colour. Teal is gone in favour of the olive and rust
      vanilla actually uses.
Version: 0.6.8
Date: 2026-08-28
  Changes:
    - The machines are worn METAL, not painted teal. An earlier pass made
      every surface dielectric to rescue saturation, which is right for
      paint and wrong for this mod - vanilla's machines are olive, rust
      and warm grey steel, and the blue this set carried was the loudest
      wrong note in it. Body panels are metallic with heavy noise-driven
      wear; teal survives only as an accent, the way vanilla uses it; and
      rust is now the one genuinely saturated colour, placed on joints,
      fasteners and wherever two parts meet.
      Measured against the vanilla assembler, the Note Press now sits at
      median luminance 51 against 51, and mean hue 74 degrees against 80.
    - Visible MECHANISM. There was nothing in the kit that read as a
      moving machine, so chains, gear trains, exposed pistons and grease
      were added: the Press is chain-driven off sprockets in its crown,
      with a three-gear train on its front flank, a second train lying
      flat on the crown, and a piston beside each column that extends as
      the ram falls.
  Bugfixes:
    - The Note Press was CROPPED in the render. A 47 degree camera
      projects height upward, so a machine 3.1 tiles tall reaches 2.3
      tiles above its own centre - and the frame only covered 2.6 in
      total. Its top-left corner was cut off before anything downstream
      ever saw it. Span raised to 6.4.
    - Added a clip check to pack.py, because nothing could have caught
      that: the pixels were never drawn, so no later step could recover
      them. It fails the build if any body frame's alpha touches its own
      frame edge. On its first run it immediately found a SECOND case -
      the Washer's shipped art is clipped at the top - which had been in
      the mod since 0.6.5 unnoticed.
    - Mechanism placed at positive Y sits behind the columns and the ram
      and is invisible to a camera looking down +Y. The first gear train,
      both chains and both pistons were built entirely hidden. They are
      on the front face and the crown now.
Version: 0.6.7
Date: 2026-08-28
  Changes:
    - Note Press, second pass, after seeing it in world next to a vanilla
      assembler. Three things were wrong that a black preview background
      hid completely:
      The pressed stack was about 40 percent of the visible area, pale and
      flat, and read as a blank label rather than as paper. It is small,
      dark and half under the ram now.
      The machine was a thin frame around a hole. A vanilla machine is a
      solid chunk that occupies its tiles, so the bed and side housings
      now fill the three by three.
      It was one slate blue. Vanilla carries teal oxidation, rust, brass
      and near-black in the same object, so the press does too.
  Bugfixes:
    - Key light energy was an exposure error, not a preference. At 5.6 the
      machines measured a median luminance of 77 against vanilla-s 41 to
      51, so they sat on the ground like lit props rather than buildings -
      and darkening the base colours could not fix it, because the lit
      faces were simply over-exposed. Cut to 3.1; median is 59 now.
Version: 0.6.6
Date: 2026-08-28
  Changes:
    - The Note Press is rebuilt as its own machine rather than the shared
      cabinet with a ram on it. It is an open H-frame you can see through:
      two heavy columns, a crown carrying a hydraulic pack and oil
      reservoir, tie rods with nuts down both sides, a spoked flywheel and
      belt drive, a ram on a piston rod that visibly shortens as it
      descends, and an offcut tray under the bed.
      This is the first of ten. Every machine shared one chassis and one
      fixed arrangement of hose, pipe and junction boxes, varying only a
      seeded scatter - which made them ten copies of one machine rather
      than ten machines. The rest follow.
  Bugfixes:
    - kit.ring() silently ignored axis="x" and left the ring lying flat on
      the ground, so the flywheel rendered as a hoop in the dirt beside
      the press. The same gap affected the Washer's end-plate bolts, the
      Shredder's motor and the Strapper's reel, none of which had been
      rendered with it yet.
    - The flywheel faced along X, which is edge-on to a camera looking
      down +Y, so a half-tile wheel drew as a 0.16-tile sliver.
Version: 0.6.5
Date: 2026-08-28
  Features:
    - THE PROSPECTOR. Deposits have always been placed by the map
      generator and nothing ever pointed at one, so a contract naming a
      currency you had not happened to walk past was a demand to go and
      wander. The Handler panel now has a Prospect button. It spends one
      Survey charge and reports the nearest deposit of the assigned
      currency as a distance and a compass bearing, charts the area, and
      drops a labelled pin on the map.
      If no deposit of that currency exists in terrain the game has
      generated yet, the charge pushes the explored frontier outward by
      one band instead and says so - which is why charges are consumable
      and cheap (8 coin for 4) rather than a one-off unlock.
      Charges are buyable from contract one. Gating them behind a random
      unlock draw would mean the earliest contracts, which need them
      most, are the ones that cannot have them.
  Changes:
    - Everything in the wash chain runs ten at a time instead of a
      hundred: laundering, drying, UV scanning, strapping and shredding.
      Energy times scaled with them, so throughput per second is
      unchanged - the line just ticks over visibly instead of sitting
      idle and then emitting one item, and a stall is obvious at a
      glance.
      Two things were scaled to keep this from quietly rebalancing the
      game. Detergent: laundering used 2 per 100 notes and the smallest
      whole amount at a batch of 10 is 1, which would have been five
      times the detergent per note - so the Scrubber yields 25 instead of
      5 and solvent takes 15 instead of 3, holding water-per-note at
      exactly 0.4. And contract counts: a strap is worth a tenth of what
      it was, so every packed-form demand on the ladder is ten times
      larger. A "strapped" contract is 20-40 straps instead of 2-4, which
      is the same 200-400 notes it always was.
    - Coins stack to 1,000,000. They are pure currency with no logistics
      cost - never belted, never smelted, and the only thing they do is
      sit somewhere until the catalogue takes them - so a stack limit on
      them was friction with no decision attached.
    - The machines are far denser. Put beside a vanilla rocket silo the
      first renders read as toys, and the reason was not shading or
      palette, it was COUNT: a vanilla machine is roughly 80% covered in
      pipework, ribbed hose, cable runs, junction boxes, grating and
      hazard stripes, and these had about sixty parts each with most of
      the deck left as flat paint. Added ribbed hose, sagging cable,
      recessed grating, skewed hazard chevrons, junction boxes, gauges,
      valves, louvre banks and ~46 pieces of seeded clutter per machine,
      all deterministic. Colour depth went from 8.9k to ~14k against
      vanilla's 20k.
    - Deep shadows. Ambient was at 0.62, which lifted every recess off
      the floor: renders measured a 5th-percentile luminance of 44
      against vanilla's 11, so nothing was ever properly dark and the
      whole machine read as plastic. Ambient is 0.20 now, with the fill
      and rim lights cut to match. Contact shadow is what makes a greeble
      look attached rather than laid on top.
    - Stacked paper is drawn as layered sheets rather than one solid
      slab. A single cream box was the largest flat area on the Note
      Press and had no edges for light to do anything with.
Version: 0.6.4
Date: 2026-08-27
  Bugfixes:
    - 0.6.3 would not load: the Dispatch Inserter's ENTITY still pointed at
      a machine icon that had been deleted when it went back to vanilla
      art. Only the item was switched over.
    - Added gen/check_files.py, because nothing existing could have caught
      that. A prototype naming a PNG that is not on disk passes both
      --dump-data and --create cleanly, since neither headless mode loads
      pixel data, and then fails in the real game. The check resolves the
      concatenated path locals this mod builds icon paths from
      (MG .. "name.png") and verifies all 243 of them exist. package.py
      now runs it before writing an archive.
    - The Incinerator kept a dead reference to a deleted icon inside a
      guard that never runs. Removed; it keeps the boiler's own icon, which
      is what its item already used, so held and placed now match.
Version: 0.6.3
Date: 2026-08-27
  Features:
    - Ten machines are rendered art instead of drawn art. The Washer,
      Note Press, Sorter, Cash Dryer, Shredder, Scrubber, Strapper,
      Paperwork Office, UV Scanner and Requisition Terminal are now
      Blender renders, described in gen/render/ as a table of primitives
      and shaded by Cycles - so they still regenerate from source like
      everything else in this mod.
      The camera angle was measured off vanilla rather than guessed: the
      rocket silo's circular mouth renders at h/w 0.673, and acos(0.673)
      is 47.7 degrees. A test box at 47 degrees matches the vanilla
      assembler's silhouette to 91.5%.
      Each machine's identifying feature faces UPWARD, because at that
      angle the top is the primary read and the front is a foreshortened
      strip. The Washer opens from the top, the Press ram comes down into
      view, the Shredder's rollers are visible in the bite.
      All ten animations are verified as exact loops: pack.py renders one
      frame past the end and requires it to be byte-identical to frame 0.
      That check caught the Sorter, whose bin lamps went dark on the wrap
      frame because a modulo sat outside an integer division.
    - The Incinerator and the Dispatch Inserter deliberately keep vanilla
      art. A boiler needs four directional structures whose footprint
      flips 3x2 to 2x3, and an inserter needs a whole hand and platform
      set; neither is a single body render. They take vanilla ICONS to
      match, so what is in your hand looks like what you put down.
  Changes:
    - Condition is gone. Notes carried a quality grade - Poor, Fine, Very
      Fine, Uncirculated, Mint - contracts demanded a minimum, and the
      Note Press existed to raise it. It was a fourth axis to satisfy on
      top of currency, denomination and packaging, and there was no
      decision in it: the answer was always "run it through the press
      again". Every quality_min / quality_max / quality_change is removed,
      contracts no longer name a condition, the Handler no longer filters
      its slots by quality, and the assignment panel has lost its
      condition chip.
    - The Note Press keeps its machine and gets a better job: 25
      counterfeit bills + 2 press oil now yield 15 unsorted notes of any
      currency you choose. Counterfeits were pure waste - shreddable for
      pulp and otherwise a tax on every deposit - and this turns the one
      worthless extraction band into the only way to produce a currency
      you have no deposit for, which matters once contracts start naming
      reserve currencies that may be nowhere near your base.
    - Unsorted piles now burn for 10 MJ instead of 1. A pile sorts into
      roughly 2.8 notes, so while both burned for the same value it was
      always correct to sort first and burn the change - which quietly
      made the Sorter mandatory on the power path as well as the delivery
      path. Burning a raw pile now beats sorting-then-burning by about
      3.5x, and sorting goes back to being what you do to notes you
      intend to ship. Denominated notes are unchanged at 1 MJ.
Version: 0.6.2
Date: 2026-08-27
  Features:
    - The bay doors open. They were baked into the Handler's static picture,
      and a picture layer cannot move, so they were painted shut - the
      rocket simply appeared through a closed roof. They are drawn per bay
      now and slide apart on vanilla's own offsets over door_opening_speed,
      after the alarm has finished its three blinks and before anything
      rises. The bay shuts again behind the launch.
      They are drawn UNDER the Handler rather than over it: the silo body
      sprite is transparent through the middle, so the doors show through
      the opening and the structure's own edges still overlap them.
    - The rocket has its engine flame, using vanilla's additive glow
      animation. It lights at the top of the rise, not at spawn, so the
      order reads alarm -> doors -> slow rise -> ignition -> climb.
  Bugfixes:
    - The rocket's engine bell hung below the silo in open air. The pod
      sprite ships a shift of by_pixel(-4, 20) in the .lua beside it, which
      was being applied on top of the draw position and pushed the bell to
      0.64 tiles past the front lip. The lip's centre column is only solid
      from +2.19 to +4.36 tiles, measured off its alpha; the rocket now
      rests at -1.70 so the bell lands at +4.18, inside that band.
    - The rocket's shadow carried the same problem at four times the size -
      its sprite shift is by_pixel(151, 185.5), nearly six tiles down and
      right. Both shifts are now zeroed in the prototype and the position
      is owned by the draw call, so there is one source of truth.
Version: 0.6.1
Date: 2026-08-27
  Bugfixes:
    - The dispatch rocket never actually flew. It appeared, stood still for
      thirty seconds, and was then deleted where it stood.
      When the rocket stopped being a real entity and became a drawn
      sprite, the code that moved it was never converted with it: the
      flight loop still called r.teleport() on `r`, a name that does not
      exist in that scope. Every use sat inside a bare pcall, so the nil
      global raised, was swallowed, and reported nothing. The rocket now
      moves by reassigning its render target, and the game logs a
      read-back check the first time a launch runs, so a silent failure
      here cannot repeat.
    - Height gained was measured as (f.start_y or f.y) - f.y against a
      field nothing ever assigned, so it was always zero and the rocket
      could only ever leave by timing out. The launch pad Y is now
      recorded when the flight begins.
    - The hard-stop timer was 30s, which is roughly the length of a real
      flight rather than "far past" it, so it fired at almost the same
      moment the rocket should have exited. Raised to 60s; the altitude
      exit is what ends a healthy flight.
    - The rocket's engine bell drew on top of the bay it was supposed to
      be sitting inside. The Handler wears the silo's front lip as part of
      its picture, but that draws on the entity layer and the rocket flies
      above it. The lip is now drawn a second time above the rocket, so
      the base is hidden until it clears the structure.
    - The silo mouth ignored vanilla's own shift for that sprite and sat
      five pixels left and half a tile high of where it belonged.
    - A flight begun before this version has no `front` sprite, and the
      cleanup loop used ipairs, which stops at the first nil - leaking the
      warning light. Cleanup now walks an explicit key list.
Version: 0.6.0
Date: 2026-08-27
  Features:
    - Every machine has its own body and its own animation. All twelve were
      wearing vanilla assembler art with a colour tint, which never worked:
      crafting_machine_tint only recolours the two masked layers vanilla's
      sheets happen to expose, so a Washer, a Shredder and a Sorting Table
      were the same three pistons in three shades of grey. From across a
      base you could not tell which building was doing what, which is the
      one thing a factory's art has to tell you.
      The Washer's paddles swing; the Dryer's drum tumbles a load that
      orbits AND turns over; the Note Press drops a platen onto a stack and
      squashes it; the Shredder's counter-rotating rollers chew and drop
      confetti into a bin you can see through the window; the Strapper's
      gantry head comes down and a band tightens; the Scrubber's impeller
      spins and its stack vents; the UV Scanner sweeps a violet lamp across
      a glass bed; the Sorter's shuttle traverses over three bins and drops
      into whichever one is lit; the Paperwork Office stamps a form and
      leaves a mark; the Requisition Terminal scrolls a ledger and blinks a
      cursor; the Incinerator burns.
      Drawn with Pillow by gen/gen_entities.py, like every other pixel in
      this mod. 2x art at scale 0.5 on Factorio's own convention, base and
      shadow stored once with the moving parts on their own cropped sheet,
      and emissive layers in working_visualisations so they go dark the
      moment a machine idles.
  Changes:
    - Machine icons are drawn too, instead of borrowing base's assembler
      and furnace icons.
    - The Incinerator has four directional structures, so its steam outlet
      now leaves by the side it faces.
    - The Dispatch Inserter has its own platform, arm and gripper rather
      than a fast inserter's.
  Bugfixes:
    - crafting_machine_tint is cleared on every machine that had one. It
      was doing nothing and claimed to be where the colour came from.
Version: 0.5.3
Date: 2026-08-27
  Features:
    - Note Press. Condition is now raised by a machine dedicated to it,
      rather than as a side effect of washing.
      Taking contamination OFF a note and crisping a clean note into a
      better grade are different problems, and folding them into one
      machine meant the wash/dry ring was really a quality ring wearing a
      washer's name - with no obvious thing to look at when a contract
      demanded Uncirculated.
      The Washer now only removes soiling and ink. The Note Press takes a
      clean pile, water and detergent, and returns it one grade better; it
      refuses anything already Mint, so the loop still terminates on its
      own. 90 coin, available from the start, since condition first matters
      at contract 23.
Version: 0.5.2
Date: 2026-08-27
  Changes:
    - Contracts pay roughly three times what they did. One of each starter
      machine costs 577 coin and a first contract paid 60 - a tenth of one
      basic setup, so ten contracts bought a single duplicate of the kit you
      were given. Being permanently short of machines was arithmetic, not
      bad play.
      A first contract now pays 200 and the top of the ladder 4,200, so the
      constraint is what you have unlocked and how fast you can build it
      rather than whether you can afford anything at all.
Version: 0.5.1
Date: 2026-08-27
  Changes:
    - The first hundred contracts are one currency, one concept at a time.
      Everything used to arrive at once - a second currency at 21, condition
      floors at 21, the top of the ladder at 28 - so you were learning
      washing, strapping, a new deposit and a new grade inside thirty jobs
      and permanently behind on all of them.
      Now: first washing at 23, first strap at 31, Very Fine at 45,
      Uncirculated at 67, first brick at 81, Mint at 89, second currency at
      101. Each axis has its own runway and no two land together.
    - A rung lasts ten contracts, so a mechanic becomes routine before the
      next one arrives.
    - Brick contracts cut from 1-2 and 2-4 to 1 and 1-2. Four bricks is
      12,800 notes, which was over three hours of drilling.
  Bugfixes:
    - Sorting recipes have names. A recipe takes its name from its single
      result, and sorting has four, so it showed as Unknown key
      "recipe-name.sort-dkk". Every wash, dry, launder, shred, strap, bundle
      and press recipe is now named explicitly.
Version: 0.5.0
Date: 2026-08-27
  Features:
    - Traction charge. Locomotives now run on their own fuel category and
      nothing else, so they can never eat banknotes or the wood the Scrubber
      depends on. The charge returns itself when burnt, so one per locomotive
      lasts forever - a battery being cycled, not a tank being emptied.
  Changes:
    - The catalogue is shelved. Entries are grouped by what they do - belts,
      inserters, fluids, power, storage, rail, machines, logistics - and
      sorted by price inside each group. Ordering by price alone put belts
      next to reactors next to chests, which is why the terminal read as a
      jumble.
    - Turrets, walls, gates, mines and vehicles are no longer stocked. The
      auto-shop took anything placeable, and none of it means anything in a
      mod with no combat.
    - Stone and steel furnaces removed. Like the burner inserters they want
      chemical fuel, so the only thing they could burn is the wood the
      Scrubber needs. The electric furnace is the dryer.
    - Labs removed. Every vanilla technology is disabled and the Handler is
      the progression system, so a lab had nothing to research.
  Bugfixes:
    - Locomotives, wagons and rails appear in the catalogue at all. Items
      live across a dozen prototype tables and the shop only scanned
      data.raw.item, so everything that is item-with-entity-data or
      rail-planner was silently skipped.
    - A pile of cash is no longer worth less than a single note. Sorting
      consumed ten piles to produce about three notes, making a pile worth
      32 DKK against a smallest note of 50. It now takes two, so a pile is
      worth 160 DKK and yields about 1.4 notes. Mining yields were scaled to
      match, so pacing is unchanged.
Version: 0.4.3
Date: 2026-08-27
  Features:
    - Packages now say how much cash is in them. Nothing in the game did, and
      you cannot read it off the bundle recipe without noticing it wants two
      straps of every denomination:
        strap  = 100 notes of one denomination
        bundle = 2 straps of each denomination, 800 notes
        brick  = 4 bundles, 3200 notes
      The descriptions are generated from the same constants the recipes and
      the face-value table use, so they cannot drift.
Version: 0.4.2
Date: 2026-08-27
  Bugfixes:
    - A contract can no longer strand an inserter, however many are feeding
      the bay. Meeting the target used to complete the job on the spot, which
      is exactly the moment several inserters are all reaching for the last
      slot - whoever lost was left holding a note it could neither insert nor
      drop.
      The contract now CLOSES instead: every dispatch inserter is retargeted
      to coin so no more notes are picked up, while the bay keeps its note
      filter so anything already in a hand still has somewhere to go. Only
      once every hand is empty does the job complete and the filters change.
      A fifteen second cap means a destroyed or re-aimed inserter cannot
      stall it.
    - The launch now takes every note of the contract item in the bay, not
      just the amount asked for. Closing lets a few extra land, and leaving
      them behind would block the next contract's filter on those slots.
Version: 0.4.1
Date: 2026-08-27
  Features:
    - Dispatch Inserter, the only inserter the mod touches. It filters itself
      to the standing contract, so it never picks up the wrong note in the
      first place - which is the real fix for the jamming, rather than
      unjamming afterwards. Four are issued with the starting kit and it is
      buyable from the start.
  Changes:
    - The unjam sweep is now scoped to Dispatch Inserters by name. It used to
      reach into any inserter aimed at a bay, including ones the player had
      configured themselves, which was overreach.
Version: 0.4.0
Date: 2026-08-27
  Features:
    - Full vanilla launch sequence. The alarm sounds and a red warning light
      pulses through three blinks, the silo mouth opens, and only then does
      the rocket rise - nine seconds of warning and four of doors before
      anything moves, matching times_to_blink and door_opening_speed.
  Changes:
    - The rocket is now DRAWN rather than spawned as an entity. An unattached
      rocket-silo-rocket is driven by a silo it does not have: it either sat
      with its engines lit forever or deleted itself after a few seconds, and
      drew above the ground either way because nothing managed its layer.
      Drawing it gives full control of position, layer and lifetime.
    - The rocket casts a shadow that drifts and fades as it climbs.
  Bugfixes:
    - Inserters no longer jam holding the previous contract's note. An
      inserter that picked up a 100 the moment before the job switched to a
      200 could not insert it and would not put it down. The note goes back
      where it came from, or onto the ground beside the inserter if that is
      not possible.
Version: 0.3.9
Date: 2026-08-27
  Bugfixes:
    - The dispatch bay no longer accepts junk between contracts. Filters were
      cleared on completion, leaving all 48 slots open through the sixteen
      second launch and the handover pause - so inserters filled the bay with
      whatever they happened to be holding. Idle bays now filter to coin,
      which keeps the payout arriving and everything else out.
Version: 0.3.8
Date: 2026-08-27
  Changes:
    - Dispatch rockets now use the vanilla flight profile exactly, taken from
      the rocket-silo-rocket prototype rather than estimated: a seven-second
      rise covering 2.8 tiles, 5.5 seconds of engine spool-up, then flight
      accelerating from a standstill at 0.01 tiles/tick^2. It leaves view
      around sixteen seconds, where every hand-tuned guess before it was an
      order of magnitude too fast.
    - Takeoff audio plays at engine ignition rather than at spawn, twelve
      seconds later, matching when the engines actually light.
Version: 0.3.7
Date: 2026-08-27
  Features:
    - The assignment panel now names the machine that makes the demanded
      goods, and says plainly when that machine has not been released yet.
      "Deliver 6 straps" is not actionable if you do not know a Strapper is
      what makes them.
  Bugfixes:
    - The Handler releases the equipment a job requires as part of issuing
      that job. Unlocks are a random draw, so the ladder could previously
      demand straps while the Strapper was still locked, with no way for the
      player to steer the draw toward it.
    - A brick contract releases the Paperwork Office and Shredder too, not
      just the press: bricks need film, and film needs pulp.
Version: 0.3.6
Date: 2026-08-27
  Changes:
    - Condition floors no longer appear until contract 21. A rung is also the
      contract number early on, so an authored grade on rung 3 was demanding
      washed notes on the third job - long before there is any reason to have
      built the wash and dry ring. Grade now climbs on the same 20-contract
      cadence as the currency roster.
    - A rung now lasts three contracts instead of one. The ladder used to top
      out at contract 10 and then repeat its hardest rung forever, so sealed
      bricks of reserve currency were demanded before a strapper existed. The
      top of the ladder now lands around contract 28.
    - Resulting ramp: loose notes to contract 9, first strap at 10, first
      washing at 21, first brick at 25.
Version: 0.3.5
Date: 2026-08-27
  Changes:
    - Dispatch rockets fly properly: a slow heavy lift clear of the pad over
      about two seconds, then acceleration, off screen by four and a half.
      The old constant speed read as a teleport.
    - The launch now plays the game's own silo takeoff audio, registered as a
      sound prototype since play_sound only accepts a registered path and
      there is no utility sound for a launch.
Version: 0.3.4
Date: 2026-08-27
  Bugfixes:
    - Dispatch rockets no longer strand on the pad with their engines lit. A
      rocket spawned without a silo has nothing driving its launch sequence,
      so it has to be flown and removed by script. Any already stuck beside a
      bay are swept on load.
    - Slot filters are re-applied when the mod updates, so an existing save
      gets them immediately instead of waiting for the next contract.
    - Filters now self-heal: every poll checks the bays still match the job
      and repairs them if not, so a save loaded without a version change
      cannot sit unfiltered.
    - Filter state is read back after writing and reported, because
      set_filter returning true is not proof the filter stuck.
Version: 0.3.3
Date: 2026-08-27
  Bugfixes:
    - Fixed a crash on the first completed contract. handler_output and
      handler_inventories were defined below the code that called them, so in
      pay_coins and complete they resolved to nil globals. Lua resolves names
      lexically, so a helper's position in the file is not a style question.
    - Both are now declared above every caller, and a new check scans for the
      whole bug class rather than one instance at a time - the same shape had
      already caused slot filtering to silently never run.
Version: 0.3.2
Date: 2026-08-27
  Bugfixes:
    - The Handler now actually filters its slots to the contract. A forward
      declaration sat below two of its three callers, so inside them the name
      resolved to a nil global and the guard swallowed it silently - filters
      were applied only after a contract COMPLETED, never when one was issued,
      and the bay accepted every denomination all run.
    - A Handler placed mid-contract now adopts the current filters immediately
      instead of staying open until the next assignment.
    - Filter application is logged, so a silent failure cannot recur unnoticed.
    - Added an on_load report of the restored contract, ladder position and
      registered bays, so a broken save round-trip shows up in the log rather
      than as odd behaviour later.
Version: 0.3.1
Date: 2026-08-27
  Changes:
    - Lamps and medium electric poles are available from the start. Lighting
      is not progression, and gating it behind a contract unlock meant the
      first night was spent in the dark for no design reason.
Version: 0.3.0
Date: 2026-08-27
  Features:
    - Coins. Completing a contract pays a cut, and the catalogue now accepts
      only coins - so what you mine and what you spend are separate decisions.
    - The Handler is a dispatch bay: rocket silo on the outside, filtered
      container on the inside. Slots filter to the contract, the last slot is
      permanently the till, and a rocket launches on completion.
    - Buy additional Handlers. Progress sums across every bay you own.
    - Goods accumulate visibly in the bay and are consumed at launch.
    - The currency roster widens by one every 20 contracts, ordered
      circulating then regional then reserve, so the map opens up gradually.
    - Pollution Scrubbers, built from wood and nothing else. They pull
      pollution out of the air and produce detergent and solvent.
    - Barrelled solvent, and detergent now ships in a drum.
  Changes:
    - Nothing vanilla remains. No vanilla ore generates, no vanilla recipe is
      craftable, and vanilla research is disabled.
    - No free power. Solar panels are gone; banknotes are the fuel.
    - The shop stocks itself from whatever mods are installed, pricing each
      item from its own recipe tree.
    - Scenery no longer drops dead resources - 125 drops stripped from rocks,
      ruins and stromatolites. Trees still give wood.
    - Machine-only recipes are hidden from the personal crafting screen,
      leaving the three things you can actually hand-craft.
    - Removed the Runner and Duffel Run: burner gear runs on chemical fuel,
      so the only thing it could burn was the wood the Scrubber needs.
    - Contamination cut from 38% of every deposit to 20%.
  Bugfixes:
    - Currency deposits generate at all. They needed autoplace-control
      prototypes and an entry in Nauvis's entity whitelist; without either the
      map came out barren and silent.
    - Drills no longer read 0.0/s. Deposits generated far below `normal`, so
      the infinite-resource yield ratio rounded to zero.
    - Contract length: the first job took 16.5 minutes of drilling. Counts now
      also scale to how rare the demanded denomination is, so a rung no longer
      swings between 10 and 60 minutes on the roll.
    - Coins, piles, contaminated notes, counterfeits and bullion bars can be
      selected in filters. Items are only unlocked by being a recipe RESULT,
      and none of these is made by a recipe.
    - The starting kit is issued reliably, and freeplay's pistol and plates
      are suppressed at the source rather than raced.
    - The drop box no longer respawns under you when you mine it to move it.