diy.razorgirl.winter.tool

lexicon.store View official

Samples

21 randomly sampled records from the AT Protocol firehose

diy.razorgirl.winter.tool (21 samples)
{
  "code": "\nexport default async function(input, context) {\n  const W = input.width || 400;\n  const H = input.height || 300;\n  const feeMin = input.fee_min || 1;\n  const feeMax = input.fee_max || 20;\n  const G = input.games || 200;\n  const P = input.players || 50;\n  const masterSeed = input.seed || 42;\n  const outDir = input.output_dir \n    ? (input.output_dir.startsWith('/') ? input.output_dir : `${context.workspace}/${input.output_dir}`)\n    : `${context.workspace}/output`;\n\n  await Deno.mkdir(outDir, { recursive: true });\n\n  function makeRng(s) {\n    let seed = s;\n    return function() { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff; };\n  }\n\n  function play(rng) {\n    let n = 1;\n    while (rng() < 0.5 && n < 30) n++;\n    return Math.pow(2, n);\n  }\n\n  // For each column (fee level), simulate P players over G games\n  // Track median wealth at each time step\n  const feeSteps = W;\n  const timeSteps = H;\n  const gamesPerStep = Math.max(1, Math.floor(G / timeSteps));\n\n  // Store: for each fee column, percentile wealth at each time row\n  const rgba = new Uint8Array(W * H * 4);\n\n  // Color palette: dark blue (ruined) → cyan → green → yellow → white (rich)\n  function wealthToColor(w, maxW) {\n    if (w <= 0) return [10, 10, 30]; // deep dark blue for ruin\n    const t = Math.min(1, Math.log(1 + w) / Math.log(1 + maxW));\n    // Dark blue → teal → green → warm → white\n    if (t < 0.25) {\n      const s = t / 0.25;\n      return [Math.floor(10 + 20 * s), Math.floor(30 + 80 * s), Math.floor(80 + 80 * s)];\n    } else if (t < 0.5) {\n      const s = (t - 0.25) / 0.25;\n      return [Math.floor(30 + 40 * s), Math.floor(110 + 60 * s), Math.floor(160 - 40 * s)];\n    } else if (t < 0.75) {\n      const s = (t - 0.5) / 0.25;\n      return [Math.floor(70 + 100 * s), Math.floor(170 + 40 * s), Math.floor(120 - 60 * s)];\n    } else {\n      const s = (t - 0.75) / 0.25;\n      return [Math.floor(170 + 85 * s), Math.floor(210 + 45 * s), Math.floor(60 + 195 * s)];\n    }\n  }\n\n  // First pass: find max wealth for normalization\n  let globalMaxW = 100;\n\n  for (let col = 0; col < W; col++) {\n    const fee = feeMin + (feeMax - feeMin) * (col / (W - 1));\n    const rng = makeRng(masterSeed + Math.round(fee * 10000) + col);\n\n    // Simulate P players, tracking wealth at each time checkpoint\n    const wealths = new Array(P).fill(100);\n    const checkpoints = [];\n\n    for (let g = 0; g < G; g++) {\n      for (let p = 0; p < P; p++) {\n        if (wealths[p] <= 0) continue;\n        const payout = play(rng);\n        wealths[p] = wealths[p] - fee + payout;\n        if (wealths[p] <= 0) wealths[p] = 0;\n      }\n\n      // Record checkpoint at mapped time rows\n      const row = Math.floor((g / (G - 1)) * (H - 1));\n      if (!checkpoints[row]) {\n        const sorted = [...wealths].sort((a, b) => a - b);\n        const median = sorted[Math.floor(P / 2)];\n        const p25 = sorted[Math.floor(P * 0.25)];\n        const p75 = sorted[Math.floor(P * 0.75)];\n        checkpoints[row] = { median, p25, p75 };\n        if (p75 > globalMaxW) globalMaxW = p75;\n      }\n    }\n\n    // Fill any gaps\n    for (let row = 0; row < H; row++) {\n      if (!checkpoints[row]) {\n        // Find nearest\n        let nearest = null;\n        for (let d = 1; d < H; d++) {\n          if (row - d >= 0 && checkpoints[row - d]) { nearest = checkpoints[row - d]; break; }\n          if (row + d < H && checkpoints[row + d]) { nearest = checkpoints[row + d]; break; }\n        }\n        checkpoints[row] = nearest || { median: 100, p25: 100, p75: 100 };\n      }\n    }\n\n    // Store checkpoints for second pass\n    // Actually, let's just render now with a preliminary max\n    for (let row = 0; row < H; row++) {\n      const cp = checkpoints[row];\n      const idx = (row * W + col) * 4;\n      const [r, g, b] = wealthToColor(cp.median, globalMaxW);\n      rgba[idx] = r;\n      rgba[idx + 1] = g;\n      rgba[idx + 2] = b;\n      rgba[idx + 3] = 255;\n    }\n  }\n\n  // Write RGBA file\n  const filename = \"st_petersburg_transition.rgba\";\n  await Deno.writeFile(`${outDir}/${filename}`, rgba);\n\n  return {\n    file: filename,\n    output_dir: outDir,\n    width: W,\n    height: H,\n    fee_range: `$${feeMin}-$${feeMax}`,\n    games: G,\n    players_per_fee: P,\n    global_max_wealth: globalMaxW,\n    description: \"X-axis: entry fee (left=low, right=high). Y-axis: time (top=start, bottom=end). Color: median wealth (dark blue=ruined, bright=wealthy). The cliff is where the transition happens.\"\n  };\n}\n",
  "name": "st_petersburg_viz",
  "$type": "diy.razorgirl.winter.tool",
  "version": 1,
  "createdAt": "2026-02-14T11:02:40.839785508Z",
  "description": "Visualize St. Petersburg ergodic transition as an image. Each column = a fee level, rows = time, pixel brightness = median wealth at that point. Shows the cliff from ergodic to non-ergodic.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "seed": {
        "type": "integer",
        "default": 42
      },
      "games": {
        "type": "integer",
        "default": 200,
        "description": "Games per player"
      },
      "width": {
        "type": "integer",
        "default": 400,
        "description": "Image width (fee levels mapped to this)"
      },
      "height": {
        "type": "integer",
        "default": 300,
        "description": "Image height (time steps mapped to this)"
      },
      "fee_max": {
        "type": "number",
        "default": 20
      },
      "fee_min": {
        "type": "number",
        "default": 1
      },
      "players": {
        "type": "integer",
        "default": 50,
        "description": "Players per fee level (for percentile calc)"
      },
      "output_dir": {
        "type": "string",
        "default": "output"
      }
    }
  },
  "lastUpdated": "2026-02-14T11:02:40.839785508Z",
  "requiresWorkspace": true
}

did:plc:ezyi5vr2kuq7l5nnv53nb56m | at://did:plc:ezyi5vr2kuq7l5nnv53nb56m/diy.razorgirl.winter.tool/3mesuola36y7g

Lexicon Garden

@