This website is meant to be read and understood quickly by humans, but is only fully parsable, on a technical level, with the aid of an AI system. Read why →
Loop MMT
Generate a Bounded 2-D Grid as a Deterministic JSONL Streamsource← all gifts

grid-source

grid-source takes grid dimensions in and emits one JSON record per cell — {row,col}, plus a value under --index/--fill — in a stable, byte-identical ROW-MAJOR order on every machine. It is the bounded 2-D coordinate substrate the spatial apps (a sudoku board, a spreadsheet range, a graphing lattice, a game board) all lean on, and it has no supply in the corpus. Unlike a filesystem or stream source there is NO provider to inject: a grid is fully determined by its dimensions, so the pure core grid(opts) has no I/O at all — pure by construction, the stronger determinism guarantee. It fixes the three quiet failures of the hand-rolled nested loop: non-deterministic/ambiguous emission order (grid-source is stable row-major, --transpose for column-major), off-by-one/unbounded dimensions (positive integers required, fail-closed, 0x0 is the honest empty stream), and coordinate/value confusion (row/col are always position; value only under --index or --fill). It pairs with grid-sink: `grid-source --cells | grid-sink` renders a real SVG.

The honest edge
grid-source emits a bounded, stable ROW-MAJOR stream of {row,col} cells (value only under --index/--fill). It is a coordinate SOURCE, not a renderer (pipe --cells into grid-sink to draw), does NOT read stdin (dimensions are flags), does NOT do sparse grids, and does NOT carry data beyond a constant --fill or the row-major --index. Dimensions must be non-negative integers; 0x0 is the empty stream.
Run it
node grid-source.js --rows 3 --cols 4 # -> row-major JSONL of 12 {row,col} cells test_grid-source.js (96/96, independent flat-index div/mod oracle + --cells composition contract) + Plumb conformance GREEN (137/137, signed 2026-09-13, non-vacuous: a column-major mutant caught on a non-square grid + a bounds-guard-stripped mutant caught) Node / browser, no dependencies
The code — every file that ships
grid-source.js245 lineson GitHub →
#!/usr/bin/env node
/* grid-source.js — generate a bounded 2-D grid as a deterministic JSONL stream of cells.
   Dependency-free, deterministic, MIT. Runs in Node (the CLI) or a browser (the pure core).

   WHAT IT IS. A SOURCE: it takes grid dimensions in and emits a JSONL stream out — one record
   per cell, in a stable row-major order — the front of a pipe that lets the fold/filter/
   transform/sink gifts work on a 2-D coordinate space:

     node grid-source.js --rows 3 --cols 3 | node grid-sink.js
     node grid-source.js --rows 9 --cols 9 --index | node schema-filter.js ...

   Each record is a fixed, portable shape: {"row":0,"col":0} — plus "value" when a value mode
   is chosen. The coordinate shape is exactly what grid-sink consumes ({row,col,...}), so
   `grid-source | grid-sink` composes into a render pipe; it is the input substrate the spatial
   apps (a sudoku board, a spreadsheet range, a graphing lattice, a Mandelbrot plane, a game
   board) all lean on — a bounded, reproducible coordinate space with no supply in the corpus.

   THE QUIET FAILURES IT FIXES. Everyone hand-rolls a nested `for (r) for (c)` and everyone gets
   it wrong in ways that only bite on the input they didn't test:

     1. NON-DETERMINISTIC / AMBIGUOUS ORDER. Ad-hoc grid loops emit in whatever order the code
        happened to nest (row-major here, column-major there), so two callers' streams don't
        line up and can't be diffed or pinned. grid-source emits a STABLE ROW-MAJOR pre-order
        (row 0 left-to-right, then row 1, ...), the same stream on every machine and every run.

     2. OFF-BY-ONE / UNBOUNDED DIMENSIONS. A grid built from an unchecked `--rows`/`--cols` (a
        float, a negative, a zero, a non-number) silently produces a wrong or infinite stream.
        grid-source requires POSITIVE INTEGER dimensions and fails CLOSED (exit 2, one-line
        message) on anything else — a 0×0 grid is the empty stream, not an error, but a
        fractional or negative dimension is refused up front.

     3. COORDINATE/VALUE CONFUSION. Hand loops mix the cell's POSITION with its CONTENT, so a
        downstream sink can't tell which field is which. grid-source keeps them separate and
        named: `row`/`col` are always the position; `value` (only when a value mode is asked
        for) is the content — a constant `--fill`, or the cell's row-major `--index`.

   THE MODEL. The PURE CORE is `grid(opts)`: it takes options (rows, cols, value mode) and returns
   the sorted, deterministic array of cell records. There is no I/O in the core — a grid is fully
   determined by its dimensions, so unlike a filesystem or a stream source there is no provider to
   inject; the core is pure by construction. The CLI parses argv into opts and renders JSONL; a
   browser calls `grid(opts)` directly.

     --rows R         number of rows (positive integer; required unless --cols implies a square via --size)
     --cols C         number of columns (positive integer; required unless --size)
     --size N         shorthand for --rows N --cols N (a square grid)
     --index          add a "value" field: the cell's 0-based row-major index (0..rows*cols-1)
     --fill V         add a "value" field: the constant V (a JSON scalar: number, string, true/false/null)
     --origin-one     number rows/cols from 1 instead of 0 (1..rows, 1..cols)
     --transpose      emit in COLUMN-major order instead of row-major (col 0 top-to-bottom, then col 1)

   DETERMINISM. grid(opts) is a pure function of opts. Given the same opts, the output is byte-
   identical on every run and every machine: cells in stable row-major (or, with --transpose,
   column-major) order, coordinates and value separated, no clock, no randomness. --index and
   --fill are mutually exclusive (a cell has at most one value).

   USAGE
     node grid-source.js --rows 3 --cols 4
     node grid-source.js --size 9 --index
     node grid-source.js --rows 2 --cols 2 --fill 0 | node grid-sink.js
     node grid-source.js --help

   Exit codes: 0 success (including an empty grid -> empty stream) · 2 usage error (unknown
   option, missing/duplicate/invalid dimension, --index with --fill, bad --fill scalar). A clean
   one-line message on stderr, never a stack trace.

   Released under MIT. Its edge is printed in the README: grid-source emits a bounded, row-major
   (or --transpose column-major) stream of {row,col[,value]} cells. It does NOT lay out or render
   (pipe into grid-sink for that), does NOT read any input (dimensions come from flags, not stdin),
   does NOT do sparse/irregular grids (every cell in the rectangle is emitted), and does NOT carry
   per-cell data (use --fill for a constant or pipe through a transform to attach real values).
*/
"use strict";

/* ==================================================================
   THE PURE CORE — grid(opts) -> [cell, ...]
   No I/O, no provider: a grid is fully determined by its dimensions.
     opts.rows / opts.cols  — positive integers (0 allowed -> empty stream)
     opts.originOne         — number from 1 instead of 0
     opts.transpose         — column-major instead of row-major
     opts.valueMode         — undefined | 'index' | 'fill'
     opts.fill              — the constant value when valueMode === 'fill'
   Returns an array of { row, col [, value] } in stable order.
   ================================================================== */
function grid(opts) {
  opts = opts || {};
  var rows = opts.rows;
  var cols = opts.cols;
  if (!isNonNegInt(rows) || !isNonNegInt(cols)) {
    throw new Error("grid: rows and cols must be non-negative integers");
  }
  var base = opts.originOne ? 1 : 0;
  var transpose = !!opts.transpose;
  var valueMode = opts.valueMode; // undefined | 'index' | 'fill'
  var fill = opts.fill;

  var out = [];
  // The row-major index is ALWAYS assigned in row-major order (r*cols + c), independent of
  // emission order, so --index is a stable property of the cell, not of the traversal. This
  // means --transpose changes the ORDER cells are emitted but NOT a cell's --index value.
  var asBlocks = !!opts.cells; // --cells: emit unit blocks {row,col,w,h} that grid-sink consumes
  function pushCell(r, c) {
    var rec = { row: base + r, col: base + c };
    if (asBlocks) { rec.w = 1; rec.h = 1; }
    if (valueMode === "index") rec.value = r * cols + c;
    else if (valueMode === "fill") rec.value = fill;
    out.push(rec);
  }

  if (!transpose) {
    for (var r = 0; r < rows; r++) {
      for (var c = 0; c < cols; c++) pushCell(r, c);
    }
  } else {
    for (var cc = 0; cc < cols; cc++) {
      for (var rr = 0; rr < rows; rr++) pushCell(rr, cc);
    }
  }
  return out;
}

// A non-negative integer (0 allowed): the dimension guard.
function isNonNegInt(n) {
  return typeof n === "number" && isFinite(n) && Math.floor(n) === n && n >= 0;
}

// Render cell records as JSONL text (one JSON object per line, trailing newline per record).
function toJSONL(records) {
  var s = "";
  for (var i = 0; i < records.length; i++) s += JSON.stringify(records[i]) + "\n";
  return s;
}

/* ==================================================================
   EXPORTS (browser + Node)
   ================================================================== */
if (typeof window !== "undefined") {
  window.ForestGifts = window.ForestGifts || {};
  window.ForestGifts.gridSource = { grid: grid, toJSONL: toJSONL };
}
if (typeof module !== "undefined" && module.exports) {
  module.exports = { grid: grid, toJSONL: toJSONL, isNonNegInt: isNonNegInt };
}

/* ==================================================================
   CLI (runs only when invoked directly, never on require)
   ================================================================== */

// Parse a --fill value as a JSON scalar (number, string, true/false/null). A bare token that
// isn't valid JSON is treated as a string (so `--fill x` -> "x"), but an explicitly malformed
// JSON literal (`--fill [1,`) is a usage error — we only accept SCALARS, never structures.
function parseFillScalar(tok) {
  var v;
  try { v = JSON.parse(tok); }
  catch (e) { return tok; } // not JSON -> a plain string
  if (v === null || typeof v === "number" || typeof v === "boolean" || typeof v === "string") return v;
  throw new Error("--fill must be a scalar (number, string, true, false, or null), not a structure");
}

function parseIntStrict(v, name) {
  var n = Number(v);
  if (String(v).trim() === "" || !isFinite(n) || Math.floor(n) !== n || n < 0) {
    throw new Error(name + " must be a non-negative integer");
  }
  return n;
}

function parseArgs(args) {
  var opts = {};
  var rows, cols, size;
  var i = 0;
  while (i < args.length) {
    var a = args[i];
    if (a === "--rows") { rows = parseIntStrict(args[i + 1], "--rows"); i += 2; }
    else if (a === "--cols") { cols = parseIntStrict(args[i + 1], "--cols"); i += 2; }
    else if (a === "--size") { size = parseIntStrict(args[i + 1], "--size"); i += 2; }
    else if (a === "--index") { opts.__indexSeen = true; i++; }
    else if (a === "--fill") {
      if (args[i + 1] === undefined) throw new Error("--fill requires a value");
      opts.__fillTok = args[i + 1]; i += 2;
    }
    else if (a === "--origin-one") { opts.originOne = true; i++; }
    else if (a === "--transpose") { opts.transpose = true; i++; }
    else if (a === "--cells") { opts.cells = true; i++; }
    else if (a.charAt(0) === "-") { throw new Error("unknown option " + a); }
    else { throw new Error("unexpected argument " + JSON.stringify(a) + " (grid-source takes flags, not positionals)"); }
  }
  // --size is shorthand for a square; it must not be combined with --rows/--cols
  if (size !== undefined) {
    if (rows !== undefined || cols !== undefined) throw new Error("--size cannot be combined with --rows/--cols");
    rows = size; cols = size;
  }
  if (rows === undefined || cols === undefined) throw new Error("both --rows and --cols are required (or use --size N)");
  // Resolve the value mode from the independently-tracked flags, guarding mutual exclusion in
  // EITHER order (--index --fill or --fill --index both refused).
  var indexSeen = !!opts.__indexSeen, fillSeen = opts.__fillTok !== undefined;
  if (indexSeen && fillSeen) throw new Error("--index and --fill are mutually exclusive");
  if (indexSeen) opts.valueMode = "index";
  else if (fillSeen) { opts.valueMode = "fill"; opts.fill = parseFillScalar(opts.__fillTok); }
  delete opts.__indexSeen; delete opts.__fillTok;
  opts.rows = rows; opts.cols = cols;
  return opts;
}

var HELP =
  "grid-source.js — generate a bounded 2-D grid as a deterministic JSONL stream of cells.\n\n" +
  "  node grid-source.js --rows 3 --cols 4\n" +
  "  node grid-source.js --size 9 --index\n" +
  "  node grid-source.js --rows 2 --cols 2 --fill 0 | node grid-sink.js\n" +
  "  node grid-source.js --help\n\n" +
  "  --rows R        number of rows (non-negative integer)\n" +
  "  --cols C        number of columns (non-negative integer)\n" +
  "  --size N        shorthand for --rows N --cols N (a square)\n" +
  "  --index         add a \"value\" field: the cell's 0-based row-major index\n" +
  "  --fill V        add a \"value\" field: the constant JSON scalar V\n" +
  "  --origin-one    number rows/cols from 1 instead of 0\n" +
  "  --transpose     emit in column-major order instead of row-major\n" +
  "  --cells         emit each cell as a unit block {row,col,w:1,h:1} (grid-sink input)\n\n" +
  "Emits one JSON object per cell: { row, col[, value] }, cells in stable ROW-MAJOR order\n" +
  "(or column-major with --transpose). The {row,col} shape is what grid-sink consumes, so\n" +
  "`grid-source --cells | grid-sink` composes. --index and --fill are mutually exclusive.\n\n" +
  "Edge: grid-source does NOT render (pipe into grid-sink), does NOT read stdin (dimensions\n" +
  "are flags), does NOT do sparse/irregular grids (every cell is emitted), and carries no\n" +
  "per-cell data (use --fill or a downstream transform).\n";

function main(argv) {
  var args = argv.slice(2);
  if (args.indexOf("--help") !== -1 || args.indexOf("-h") !== -1) {
    process.stdout.write(HELP);
    return 0;
  }
  var opts;
  try { opts = parseArgs(args); }
  catch (e) { process.stderr.write("grid-source: " + e.message + "\n"); return 2; }

  var records;
  try { records = grid(opts); }
  catch (e) { process.stderr.write("grid-source: " + e.message + "\n"); return 2; }

  process.stdout.write(toJSONL(records));
  return 0;
}

if (typeof require !== "undefined" && require.main === module) {
  process.exitCode = main(process.argv);
}
test_grid-source.js135 lineson GitHub →
#!/usr/bin/env node
/* test_grid-source.js — battery for the grid-source gift.
   node test_grid-source.js  ->  exit 0 PASS / non-zero FAIL.

   The oracle is INDEPENDENT: the gift walks two nested loops (for row / for col); the oracle
   generates cells from a FLAT index (0..rows*cols-1) and maps each index back to (row,col) by
   division/modulo — a different route to the same set, so agreement proves the gift's ordering
   and coordinates rather than re-running its own logic. Plus frozen hand goldens for each of the
   three quiet failures and the fail-closed dimension edges.
*/
"use strict";
var G = require("./grid-source.js");
var grid = G.grid, toJSONL = G.toJSONL;

var pass = 0, fail = 0;
function ok(name, cond) { if (cond) { pass++; } else { fail++; console.log("  FAIL  " + name); } }
function eq(name, a, b) { ok(name, JSON.stringify(a) === JSON.stringify(b)); }

/* ---- INDEPENDENT ORACLE: flat-index -> (row,col), a different route than nested loops ---- */
function oracle(opts) {
  var rows = opts.rows, cols = opts.cols;
  var base = opts.originOne ? 1 : 0;
  var n = rows * cols;
  var cells = [];
  for (var k = 0; k < n; k++) {
    // row-major flat index -> coordinates
    var r = Math.floor(k / cols);
    var c = k % cols;
    var rec = { row: base + r, col: base + c };
    if (opts.valueMode === "index") rec.value = r * cols + c; // == k in row-major
    else if (opts.valueMode === "fill") rec.value = opts.fill;
    cells.push(rec);
  }
  if (opts.transpose) {
    // re-sort into column-major order WITHOUT recomputing index (index stays row-major)
    cells.sort(function (a, b) {
      var ac = a.col, bc = b.col, ar = a.row, br = b.row;
      if (ac !== bc) return ac - bc;
      return ar - br;
    });
  }
  return cells;
}

/* ---- grid == oracle across a dimension grid ---------------------------- */
var DIMS = [[1, 1], [1, 5], [5, 1], [3, 3], [3, 4], [9, 9], [2, 7], [0, 0], [0, 3], [4, 0]];
var MODES = [
  {},
  { valueMode: "index" },
  { valueMode: "fill", fill: 0 },
  { valueMode: "fill", fill: "x" },
  { originOne: true },
  { transpose: true },
  { transpose: true, valueMode: "index" },
  { originOne: true, valueMode: "index", transpose: true }
];
for (var d = 0; d < DIMS.length; d++) {
  for (var m = 0; m < MODES.length; m++) {
    var opts = Object.assign({ rows: DIMS[d][0], cols: DIMS[d][1] }, MODES[m]);
    var got = grid(opts);
    var want = oracle(opts);
    eq("grid==oracle dims=" + DIMS[d] + " mode#" + m, got, want);
  }
}

/* ---- QUIET FAILURE 1: stable row-major order (not column-major by accident) ---- */
(function () {
  var g = grid({ rows: 2, cols: 3 });
  // row-major: (0,0)(0,1)(0,2)(1,0)(1,1)(1,2)
  eq("QF1 row-major order", g.map(function (x) { return [x.row, x.col]; }),
     [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]);
  var t = grid({ rows: 2, cols: 3, transpose: true });
  // column-major: (0,0)(1,0)(0,1)(1,1)(0,2)(1,2)
  eq("QF1 --transpose column-major order", t.map(function (x) { return [x.row, x.col]; }),
     [[0, 0], [1, 0], [0, 1], [1, 1], [0, 2], [1, 2]]);
})();

/* ---- QUIET FAILURE 2: bounded/valid dimensions (guard is in the CLI; core guards too) ---- */
(function () {
  var threw = false;
  try { grid({ rows: 2.5, cols: 2 }); } catch (e) { threw = true; }
  ok("QF2 core throws on fractional rows", threw);
  threw = false;
  try { grid({ rows: -1, cols: 2 }); } catch (e) { threw = true; }
  ok("QF2 core throws on negative rows", threw);
  // 0x0 is the empty stream, NOT an error
  eq("QF2 0x0 is the empty grid", grid({ rows: 0, cols: 0 }), []);
  eq("QF2 0xN is empty", grid({ rows: 0, cols: 5 }), []);
})();

/* ---- QUIET FAILURE 3: coordinate/value separation ---- */
(function () {
  var plain = grid({ rows: 1, cols: 2 });
  ok("QF3 no value field when no value mode", plain.every(function (x) { return x.value === undefined; }));
  var idx = grid({ rows: 2, cols: 2, valueMode: "index" });
  eq("QF3 --index is row-major 0-based", idx.map(function (x) { return x.value; }), [0, 1, 2, 3]);
  var idxT = grid({ rows: 2, cols: 2, valueMode: "index", transpose: true });
  // transpose changes ORDER but index stays row-major property: (0,0)=0 (1,0)=2 (0,1)=1 (1,1)=3
  eq("QF3 --index stable under --transpose (order changes, value does not)",
     idxT.map(function (x) { return [x.row, x.col, x.value]; }),
     [[0, 0, 0], [1, 0, 2], [0, 1, 1], [1, 1, 3]]);
  var fill = grid({ rows: 1, cols: 3, valueMode: "fill", fill: 7 });
  ok("QF3 --fill is the constant", fill.every(function (x) { return x.value === 7; }));
})();

/* ---- composition: {row,col} shape, and --cells emits grid-sink's {row,col,w,h} block ---- */
(function () {
  var g = grid({ rows: 2, cols: 2 });
  ok("composition: every record has row and col (coordinate substrate)",
     g.every(function (x) { return typeof x.row === "number" && typeof x.col === "number"; }));
  var cells = grid({ rows: 2, cols: 2, cells: true });
  ok("composition: --cells emits unit blocks {row,col,w:1,h:1} (grid-sink input)",
     cells.every(function (x) { return x.w === 1 && x.h === 1 && typeof x.row === "number" && typeof x.col === "number"; }));
  eq("composition: --cells first block", cells[0], { row: 0, col: 0, w: 1, h: 1 });
})();

/* ---- --origin-one ---- */
(function () {
  var g = grid({ rows: 2, cols: 2, originOne: true });
  eq("--origin-one numbers from 1", g.map(function (x) { return [x.row, x.col]; }),
     [[1, 1], [1, 2], [2, 1], [2, 2]]);
})();

/* ---- determinism: two calls byte-identical ---- */
ok("deterministic across two grid() calls",
   toJSONL(grid({ rows: 5, cols: 5, valueMode: "index" })) === toJSONL(grid({ rows: 5, cols: 5, valueMode: "index" })));

/* ---- toJSONL surface ---- */
eq("toJSONL renders one line per cell with trailing newline",
   toJSONL([{ row: 0, col: 0 }, { row: 0, col: 1 }]),
   '{"row":0,"col":0}\n{"row":0,"col":1}\n');

/* ---- report ---- */
console.log("grid-source battery: " + pass + " passed, " + fail + " failed");
process.exitCode = fail === 0 ? 0 : 1;
Take the whole folder → MIT Node / browser, no dependencies