Title of State:

Resource Definition

Goal of Change:

Avg Node Size = starting balance baseline

Variation % (0–100) = deviation around Avg

Max Node Size = hard cap for every node of that resource

Generation % (-1000 to 1000) = stored on the node (no behavior yet)

Spawning = checkbox + % rate (stored, no behavior yet)

Also: menu window widened to cover the 1500 viewer

PATCH 0 — Widen menu window to cover viewer

Code to Remove

81 - 
  .menuPanel{
    width:980px;
    height:760px;
    position:relative;
    display:flex;
    flex-direction:column;
  }

Code to Add

81 - 
  .menuPanel{
    width:1500px;
    height:900px;
    position:relative;
    display:flex;
    flex-direction:column;
  }


PATCH 1 — Make resource rows support lots of controls (CSS)

Code to Remove

192 - 
  .resRow{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:12px;
    padding:10px 10px;
    border-radius:10px;
    border:1px solid rgba(255,255,255,.10);
    background:rgba(0,0,0,.18);
  }
  .countInput{
    width:110px;
    padding:10px 10px;
    border-radius:10px;
    border:1px solid rgba(255,255,255,.16);
    background:rgba(0,0,0,.25);
    color:#e9f0ff;
    font-size:14px;
    outline:none;
    text-align:right;
  }

Code to Add

192 - 
  .resRow{
    display:flex;
    align-items:center;
    justify-content:flex-start;
    gap:10px;
    padding:10px 10px;
    border-radius:10px;
    border:1px solid rgba(255,255,255,.10);
    background:rgba(0,0,0,.18);
    flex-wrap:wrap;
  }

  .miniLabel{
    font-size:12px;
    opacity:.75;
    user-select:none;
    white-space:nowrap;
  }

  .countInput{
    width:80px;
    padding:10px 10px;
    border-radius:10px;
    border:1px solid rgba(255,255,255,.16);
    background:rgba(0,0,0,.25);
    color:#e9f0ff;
    font-size:14px;
    outline:none;
    text-align:right;
  }

  .numInput{
    width:110px;
    padding:10px 10px;
    border-radius:10px;
    border:1px solid rgba(255,255,255,.16);
    background:rgba(0,0,0,.25);
    color:#e9f0ff;
    font-size:14px;
    outline:none;
    text-align:right;
  }

  .pctInput{
    width:90px;
    padding:10px 10px;
    border-radius:10px;
    border:1px solid rgba(255,255,255,.16);
    background:rgba(0,0,0,.25);
    color:#e9f0ff;
    font-size:14px;
    outline:none;
    text-align:right;
  }

  .spawnRow{
    display:flex;
    align-items:center;
    gap:8px;
    opacity:.9;
    font-size:12px;
    white-space:nowrap;
  }


PATCH 2 — MENU HTML: replace the 4 resource rows with full controls

Code to Remove

339 - 
                <div class="resRow">
                  <label class="chkRow">
                    <input id="resOreOn" type="checkbox" checked />
                    <span>Ore</span>
                  </label>

                  <label class="chkRow smallChk">
                    <input id="resOreHidden" type="checkbox" />
                    <span>Hidden</span>
                  </label>

                  <input id="resOreCount" class="countInput" type="number" step="1" min="0" value="40" />
                </div>

                <div class="resRow">
                  <label class="chkRow">
                    <input id="resStoneOn" type="checkbox" checked />
                    <span>Stone</span>
                  </label>

                  <label class="chkRow smallChk">
                    <input id="resStoneHidden" type="checkbox" />
                    <span>Hidden</span>
                  </label>

                  <input id="resStoneCount" class="countInput" type="number" step="1" min="0" value="35" />
                </div>

                <div class="resRow">
                  <label class="chkRow">
                    <input id="resOilOn" type="checkbox" checked />
                    <span>Oil</span>
                  </label>

                  <label class="chkRow smallChk">
                    <input id="resOilHidden" type="checkbox" checked />
                    <span>Hidden</span>
                  </label>

                  <input id="resOilCount" class="countInput" type="number" step="1" min="0" value="12" />
                </div>

                <div class="resRow">
                  <label class="chkRow">
                    <input id="resWoodOn" type="checkbox" checked />
                    <span>Wood</span>
                  </label>

                  <label class="chkRow smallChk">
                    <input id="resWoodHidden" type="checkbox" />
                    <span>Hidden</span>
                  </label>

                  <input id="resWoodCount" class="countInput" type="number" step="1" min="0" value="55" />
                </div>

Code to Add

192 - 
                <div class="resRow">
                  <label class="chkRow">
                    <input id="resOreOn" type="checkbox" checked />
                    <span>Ore</span>
                  </label>

                  <label class="chkRow smallChk">
                    <input id="resOreHidden" type="checkbox" />
                    <span>Hidden</span>
                  </label>

                  <span class="miniLabel">#</span>
                  <input id="resOreCount" class="countInput" type="number" step="1" min="0" value="40" />

                  <span class="miniLabel">Avg</span>
                  <input id="resOreAvg" class="numInput" type="number" step="1" min="0" value="700" />

                  <span class="miniLabel">Var%</span>
                  <input id="resOreVar" class="pctInput" type="number" step="1" min="0" max="100" value="20" />

                  <span class="miniLabel">Max</span>
                  <input id="resOreMax" class="numInput" type="number" step="1" min="1" value="1200" />

                  <span class="miniLabel">Gen%</span>
                  <input id="resOreGen" class="pctInput" type="number" step="1" min="-1000" max="1000" value="0" />

                  <label class="spawnRow">
                    <input id="resOreSpawnOn" type="checkbox" />
                    <span>Spawn</span>
                  </label>
                  <span class="miniLabel">Rate%</span>
                  <input id="resOreSpawnRate" class="pctInput" type="number" step="1" min="0" max="100" value="0" />
                </div>

                <div class="resRow">
                  <label class="chkRow">
                    <input id="resStoneOn" type="checkbox" checked />
                    <span>Stone</span>
                  </label>

                  <label class="chkRow smallChk">
                    <input id="resStoneHidden" type="checkbox" />
                    <span>Hidden</span>
                  </label>

                  <span class="miniLabel">#</span>
                  <input id="resStoneCount" class="countInput" type="number" step="1" min="0" value="35" />

                  <span class="miniLabel">Avg</span>
                  <input id="resStoneAvg" class="numInput" type="number" step="1" min="0" value="900" />

                  <span class="miniLabel">Var%</span>
                  <input id="resStoneVar" class="pctInput" type="number" step="1" min="0" max="100" value="15" />

                  <span class="miniLabel">Max</span>
                  <input id="resStoneMax" class="numInput" type="number" step="1" min="1" value="1600" />

                  <span class="miniLabel">Gen%</span>
                  <input id="resStoneGen" class="pctInput" type="number" step="1" min="-1000" max="1000" value="0" />

                  <label class="spawnRow">
                    <input id="resStoneSpawnOn" type="checkbox" />
                    <span>Spawn</span>
                  </label>
                  <span class="miniLabel">Rate%</span>
                  <input id="resStoneSpawnRate" class="pctInput" type="number" step="1" min="0" max="100" value="0" />
                </div>

                <div class="resRow">
                  <label class="chkRow">
                    <input id="resOilOn" type="checkbox" checked />
                    <span>Oil</span>
                  </label>

                  <label class="chkRow smallChk">
                    <input id="resOilHidden" type="checkbox" checked />
                    <span>Hidden</span>
                  </label>

                  <span class="miniLabel">#</span>
                  <input id="resOilCount" class="countInput" type="number" step="1" min="0" value="12" />

                  <span class="miniLabel">Avg</span>
                  <input id="resOilAvg" class="numInput" type="number" step="1" min="0" value="1200" />

                  <span class="miniLabel">Var%</span>
                  <input id="resOilVar" class="pctInput" type="number" step="1" min="0" max="100" value="25" />

                  <span class="miniLabel">Max</span>
                  <input id="resOilMax" class="numInput" type="number" step="1" min="1" value="2500" />

                  <span class="miniLabel">Gen%</span>
                  <input id="resOilGen" class="pctInput" type="number" step="1" min="-1000" max="1000" value="0" />

                  <label class="spawnRow">
                    <input id="resOilSpawnOn" type="checkbox" />
                    <span>Spawn</span>
                  </label>
                  <span class="miniLabel">Rate%</span>
                  <input id="resOilSpawnRate" class="pctInput" type="number" step="1" min="0" max="100" value="0" />
                </div>

                <div class="resRow">
                  <label class="chkRow">
                    <input id="resWoodOn" type="checkbox" checked />
                    <span>Wood</span>
                  </label>

                  <label class="chkRow smallChk">
                    <input id="resWoodHidden" type="checkbox" />
                    <span>Hidden</span>
                  </label>

                  <span class="miniLabel">#</span>
                  <input id="resWoodCount" class="countInput" type="number" step="1" min="0" value="55" />

                  <span class="miniLabel">Avg</span>
                  <input id="resWoodAvg" class="numInput" type="number" step="1" min="0" value="300" />

                  <span class="miniLabel">Var%</span>
                  <input id="resWoodVar" class="pctInput" type="number" step="1" min="0" max="100" value="35" />

                  <span class="miniLabel">Max</span>
                  <input id="resWoodMax" class="numInput" type="number" step="1" min="1" value="900" />

                  <span class="miniLabel">Gen%</span>
                  <input id="resWoodGen" class="pctInput" type="number" step="1" min="-1000" max="1000" value="0" />

                  <label class="spawnRow">
                    <input id="resWoodSpawnOn" type="checkbox" checked />
                    <span>Spawn</span>
                  </label>
                  <span class="miniLabel">Rate%</span>
                  <input id="resWoodSpawnRate" class="pctInput" type="number" step="1" min="0" max="100" value="5" />
                </div>


PATCH 3 — JS: grab new controls

Code to Remove

516 - 
const resOreCount   = document.getElementById("resOreCount");
const resStoneCount = document.getElementById("resStoneCount");
const resOilCount   = document.getElementById("resOilCount");
const resWoodCount  = document.getElementById("resWoodCount");

Code to Add

516 - 
const resOreCount   = document.getElementById("resOreCount");
const resStoneCount = document.getElementById("resStoneCount");
const resOilCount   = document.getElementById("resOilCount");
const resWoodCount  = document.getElementById("resWoodCount");

const resOreAvg = document.getElementById("resOreAvg");
const resOreVar = document.getElementById("resOreVar");
const resOreMax = document.getElementById("resOreMax");
const resOreGen = document.getElementById("resOreGen");
const resOreSpawnOn = document.getElementById("resOreSpawnOn");
const resOreSpawnRate = document.getElementById("resOreSpawnRate");

const resStoneAvg = document.getElementById("resStoneAvg");
const resStoneVar = document.getElementById("resStoneVar");
const resStoneMax = document.getElementById("resStoneMax");
const resStoneGen = document.getElementById("resStoneGen");
const resStoneSpawnOn = document.getElementById("resStoneSpawnOn");
const resStoneSpawnRate = document.getElementById("resStoneSpawnRate");

const resOilAvg = document.getElementById("resOilAvg");
const resOilVar = document.getElementById("resOilVar");
const resOilMax = document.getElementById("resOilMax");
const resOilGen = document.getElementById("resOilGen");
const resOilSpawnOn = document.getElementById("resOilSpawnOn");
const resOilSpawnRate = document.getElementById("resOilSpawnRate");

const resWoodAvg = document.getElementById("resWoodAvg");
const resWoodVar = document.getElementById("resWoodVar");
const resWoodMax = document.getElementById("resWoodMax");
const resWoodGen = document.getElementById("resWoodGen");
const resWoodSpawnOn = document.getElementById("resWoodSpawnOn");
const resWoodSpawnRate = document.getElementById("resWoodSpawnRate");


PATCH 4 — JS: read Avg/Var/Max/Gen/Spawn settings into readResourceSettings()

Code to Remove

784 - 
  return {
    Enabled: on,
    Ore:   { Enabled: on && oreOn,   Count: oreCount,   Hidden: !!resOreHidden.checked },
    Stone: { Enabled: on && stoneOn, Count: stoneCount, Hidden: !!resStoneHidden.checked },
    Oil:   { Enabled: on && oilOn,   Count: oilCount,   Hidden: !!resOilHidden.checked },
    Wood:  { Enabled: on && woodOn,  Count: woodCount,  Hidden: !!resWoodHidden.checked },
  };

Code to Add

784 - 
  const clamp01 = (v)=> Math.max(0, Math.min(100, v|0));
  const clampGen = (v)=> Math.max(-1000, Math.min(1000, v|0));

  const oreAvg = Math.max(0, (Number(resOreAvg.value) | 0));
  const oreVar = clamp01(Number(resOreVar.value));
  const oreMax = Math.max(1, (Number(resOreMax.value) | 0));
  const oreGen = clampGen(Number(resOreGen.value));
  const oreSpawnOn = !!resOreSpawnOn.checked;
  const oreSpawnRate = clamp01(Number(resOreSpawnRate.value));

  const stoneAvg = Math.max(0, (Number(resStoneAvg.value) | 0));
  const stoneVar = clamp01(Number(resStoneVar.value));
  const stoneMax = Math.max(1, (Number(resStoneMax.value) | 0));
  const stoneGen = clampGen(Number(resStoneGen.value));
  const stoneSpawnOn = !!resStoneSpawnOn.checked;
  const stoneSpawnRate = clamp01(Number(resStoneSpawnRate.value));

  const oilAvg = Math.max(0, (Number(resOilAvg.value) | 0));
  const oilVar = clamp01(Number(resOilVar.value));
  const oilMax = Math.max(1, (Number(resOilMax.value) | 0));
  const oilGen = clampGen(Number(resOilGen.value));
  const oilSpawnOn = !!resOilSpawnOn.checked;
  const oilSpawnRate = clamp01(Number(resOilSpawnRate.value));

  const woodAvg = Math.max(0, (Number(resWoodAvg.value) | 0));
  const woodVar = clamp01(Number(resWoodVar.value));
  const woodMax = Math.max(1, (Number(resWoodMax.value) | 0));
  const woodGen = clampGen(Number(resWoodGen.value));
  const woodSpawnOn = !!resWoodSpawnOn.checked;
  const woodSpawnRate = clamp01(Number(resWoodSpawnRate.value));

  return {
    Enabled: on,
    Ore:   { Enabled: on && oreOn,   Count: oreCount,   Hidden: !!resOreHidden.checked,   Avg: oreAvg,   Var: oreVar,   Max: oreMax,   Gen: oreGen,   SpawnOn: oreSpawnOn,   SpawnRate: oreSpawnRate },
    Stone: { Enabled: on && stoneOn, Count: stoneCount, Hidden: !!resStoneHidden.checked, Avg: stoneAvg, Var: stoneVar, Max: stoneMax, Gen: stoneGen, SpawnOn: stoneSpawnOn, SpawnRate: stoneSpawnRate },
    Oil:   { Enabled: on && oilOn,   Count: oilCount,   Hidden: !!resOilHidden.checked,   Avg: oilAvg,   Var: oilVar,   Max: oilMax,   Gen: oilGen,   SpawnOn: oilSpawnOn,   SpawnRate: oilSpawnRate },
    Wood:  { Enabled: on && woodOn,  Count: woodCount,  Hidden: !!resWoodHidden.checked,  Avg: woodAvg,  Var: woodVar,  Max: woodMax,  Gen: woodGen,  SpawnOn: woodSpawnOn,  SpawnRate: woodSpawnRate },
  };


PATCH 5 — JS: apply your Avg/Var/Max rules in node creation

Code to Remove

836 - 
  const pushN = (type, n)=>{
    for(let i=0;i<n;i++){
      const node = {
        Type: type,
        X: randRange(minX, maxX),
        Y: randRange(minY, maxY),
        Radius: 16,

        Hidden: false,
        Revealed: true,
      };
      S.resources.push(node);
    }
  };

Code to Add

836 - 
  const pushN = (type, n, cfg)=>{
    // Avg = starting balance baseline
    // Var% = 0..100:
    //   0% => start = Avg
    //   100% => start in [0, 2*Avg]
    // Max = hard cap; if start > Max, clamp to Max
    const avg = Math.max(0, cfg.Avg | 0);
    const varPct = Math.max(0, Math.min(100, cfg.Var | 0));
    const maxCap = Math.max(avg + 1, cfg.Max | 0); // enforce max > avg

    for(let i=0;i<n;i++){
      // t in [-1, +1]
      const t = (RNG() * 2) - 1;
      const start = avg * (1 + t * (varPct / 100));
      let amt = Math.floor(start);
      if(amt < 0) amt = 0;
      if(amt > maxCap) amt = maxCap;

      const node = {
        Type: type,
        X: randRange(minX, maxX),
        Y: randRange(minY, maxY),
        Radius: 16,

        MaxRemaining: maxCap,   // flat cap for the type
        Remaining: amt,         // starting balance per your rule

        GenerationPct: cfg.Gen, // stored only (no behavior yet)
        SpawnOn: !!cfg.SpawnOn, // stored only (no behavior yet)
        SpawnRate: cfg.SpawnRate, // stored only (no behavior yet)

        Hidden: false,
        Revealed: true,
      };
      S.resources.push(node);
    }
  };


Ore

Code to Remove

887 - 
    pushN("ORE", S.resourceSettings.Ore.Count);

Code to Add

887 - 
    pushN("ORE", S.resourceSettings.Ore.Count, S.resourceSettings.Ore);


Stone

Code to Remove

893 - 
    pushN("STONE", S.resourceSettings.Stone.Count);

Code to Add

893 - 
    pushN("STONE", S.resourceSettings.Stone.Count, S.resourceSettings.Stone);


Oil

Code to Remove

899 - 
    pushN("OIL", S.resourceSettings.Oil.Count);

Code to Add

899 - 
    pushN("OIL", S.resourceSettings.Oil.Count, S.resourceSettings.Oil);


Wood

Code to Remove

905 - 
    pushN("WOOD", S.resourceSettings.Wood.Count);

Code to Add

905 - 
    pushN("WOOD", S.resourceSettings.Wood.Count, S.resourceSettings.Wood);


PATCH 6 — HUD: show AMT as Remaining/MaxCap for selection

Code to Remove

1117 - 
    selLine = `\\nSEL: #${si} ${n.Type} @ ${Math.floor(n.X)},${Math.floor(n.Y)}`;

Code to Add

1117 - 
    selLine = `\\nSEL: #${si} ${n.Type} @ ${Math.floor(n.X)},${Math.floor(n.Y)}  AMT: ${n.Remaining}/${n.MaxRemaining}`;


Insert spawn function

Code to Remove

1021 -
insert line

Code to Add

1021 - 
/* =========================
   GENERIC SPAWNING
   ========================= */
function spawnFromNode(parent, dt){
  if(!parent.SpawnOn) return;

  const rate = Math.max(0, Math.min(100, parent.SpawnRate|0));
  const chancePerSecond = rate / 100;

  if(RNG() > chancePerSecond * dt) return;

  const angle = RNG() * Math.PI * 2;
  const dist = 40 + RNG() * 100;

  const nx = parent.X + Math.cos(angle) * dist;
  const ny = parent.Y + Math.sin(angle) * dist;

  if(nx < 40 || ny < 40 || nx > MAP_SIZE-40 || ny > MAP_SIZE-40) return;

  for(const r of S.resources){
    const dx = r.X - nx;
    const dy = r.Y - ny;
    if(dx*dx + dy*dy < 30*30) return;
  }

  S.resources.push({
    Type: parent.Type,
    X: nx,
    Y: ny,
    Radius: parent.Radius,
    MaxRemaining: parent.MaxRemaining,
    Remaining: parent.Remaining,
    GenerationPct: parent.GenerationPct,
    SpawnOn: parent.SpawnOn,
    SpawnRate: parent.SpawnRate,
    Hidden: false,
    Revealed: true,
  });
}


Add spawn pass inside update()

Code to Remove

1086 -
  // Clamp to map bounds
  const maxCam = MAP_SIZE - VIEW;
  S.camX = clamp(S.camX, 0, maxCam);
  S.camY = clamp(S.camY, 0, maxCam);
}

Code to Add

1086 - 
  // Clamp to map bounds
  const maxCam = MAP_SIZE - VIEW;
  S.camX = clamp(S.camX, 0, maxCam);
  S.camY = clamp(S.camY, 0, maxCam);

  // ---- Spawning pass ----
  if(S.resources && S.resources.length){
    const initialCount = S.resources.length;
    for(let i=0;i<initialCount;i++){
      const r = S.resources[i];
      if(r && r.SpawnOn){
        spawnFromNode(r, dt);
      }
    }
  }
}


Apply Generation as Units/Sec in update(dt)

Code to Remove

1091 - 
  // ---- Spawning pass ----
  if(S.resources && S.resources.length){
    const initialCount = S.resources.length;
    for(let i=0;i<initialCount;i++){
      const r = S.resources[i];
      if(r && r.SpawnOn){
        spawnFromNode(r, dt);
      }
    }
  }
}

Code to Add

1091 - 
  // ---- Generation / Decay pass ----
  if(S.resources && S.resources.length){
    for(const r of S.resources){
      if(typeof r.GenerationPct === "number"){
        const delta = r.GenerationPct * dt;   // units per second
        r.Remaining += delta;

        if(r.Remaining < 0) r.Remaining = 0;
        if(r.MaxRemaining != null && r.Remaining > r.MaxRemaining){
          r.Remaining = r.MaxRemaining;
        }
      }
    }
  }

  // ---- Spawning pass ----
  if(S.resources && S.resources.length){
    const initialCount = S.resources.length;
    for(let i=0;i<initialCount;i++){
      const r = S.resources[i];
      if(r && r.SpawnOn){
        spawnFromNode(r, dt);
      }
    }
  }
}


Rename GenerationPct to GenerationRate (cleaner, optional but correct)

Code to Remove

863 - 
        GenerationPct: cfg.Gen, // stored only (no behavior yet)

Code to Add

863 - 
        GenerationRate: cfg.Gen,


Rename GenerationPct to GenerationRate (cleaner, optional but correct)

Code to Remove

1094 - 
      if(typeof r.GenerationPct === "number"){
        const delta = r.GenerationPct * dt;   // units per second

Code to Add

1094 - 
      if(typeof r.GenerationRate === "number"){
        const delta = r.GenerationRate * dt;


Result