{
  "experimentId": "2026-08-23-model-painting-study",
  "exportedAt": "2026-08-24T02:20:26.635Z",
  "study": {
    "experimentId": "2026-08-23-model-painting-study",
    "createdAt": "2026-08-23",
    "subjects": [
      {
        "promptId": "hibiscus-core-v1",
        "prompt": "a peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper",
        "medium": "watercolor",
        "paper": "cream",
        "seed": 1701
      },
      {
        "promptId": "crow-core-v1",
        "prompt": "a crow on a telephone wire in winter fog, distant hills",
        "medium": "ink",
        "paper": "cream",
        "seed": 1702
      },
      {
        "promptId": "luna-moth-core-v1",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "medium": "watercolor",
        "paper": "night",
        "seed": 1703
      }
    ],
    "smokeModels": [
      {
        "provider": "openrouter",
        "model": "thinkingmachines/inkling"
      },
      {
        "provider": "openrouter",
        "model": "meta/muse-spark-1.2"
      },
      {
        "provider": "opencode-go",
        "model": "muse-spark-1.2-contributor"
      },
      {
        "provider": "opencode-go",
        "model": "grok-4.5"
      },
      {
        "provider": "opencode-go",
        "model": "gpt-5.6-luna"
      },
      {
        "provider": "opencode-go",
        "model": "deepseek-v4-flash"
      },
      {
        "provider": "opencode-go",
        "model": "qwen3.8-max",
        "role": "fallback after Muse access gate and DeepSeek render interruption"
      }
    ],
    "refinement": {
      "promptSpec": "directed-v3",
      "finalists": [
        {
          "provider": "openrouter",
          "model": "thinkingmachines/inkling"
        },
        {
          "provider": "opencode-go",
          "model": "grok-4.5"
        }
      ],
      "directions": {
        "hibiscus-directed-v3": "Paint one naturalistic hibiscus bloom spanning approximately x=110..475 and y=85..425. Use five overlapping, unequal 7–12-vertex petal contours around a throat near (300, 270); do not use circles for petals. Add one half-open bud near (455, 175), a curved stem descending toward (250, 560), two leaves, and two or three fallen petals in the lower-left third. Put the darkest peach-red and green marks at the throat, stamen, and stem junction. Keep tea stains extremely faint.",
        "crow-directed-v3": "Paint one large, readable side-view crow spanning approximately x=150..440 and y=135..350, facing left. Build distinct closed contours for head, beak, chest, folded wing, belly, and tail; do not use circles for the body. Run the telephone wire across y=355 and place quiet fog-softened hills only in the lower third. The crow must be the darkest and crispest mass in the image; keep the full beak and tail on-canvas.",
        "luna-moth-directed-v3": "Paint one luna moth with wings spanning approximately x=90..510 and y=100..445 and a narrow body near x=285..315. Use separate closed contours for two forewings and two hindwings, with hindwing tails extending toward y=470; symmetry may be loose but anatomy must read. Place a soft lamplight halo in the upper-right and a dark windowsill across y=510, with only a few quiet garden marks beyond. Keep wing veins sparse and organic. Do not add arbitrary polygons, framing boxes, or circular diagrams."
      }
    }
  },
  "baselines": [
    {
      "attemptId": "2026-08-23T22-53-14-a-peach-hibiscus-half-open-bud-fallen-pe",
      "status": "success",
      "round": "legacy-baseline",
      "prompt": "a peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper",
      "promptId": "hibiscus-core-v1",
      "promptSpec": "legacy-unversioned",
      "provider": "not-recorded",
      "model": "deepseek-v4-flash",
      "medium": "watercolor",
      "paper": "cream",
      "seed": null,
      "canvas": {
        "width": 600,
        "height": 600
      },
      "image": "/images/model-painting-study/2026-08-23T22-53-14-a-peach-hibiscus-half-open-bud-fallen-pe.png",
      "source": "/images/model-painting-study/2026-08-23T22-53-14-a-peach-hibiscus-half-open-bud-fallen-pe.js.txt",
      "provenanceNote": "The legacy metadata recorded the model but not provider, protocol, seed, or exact system prompt.",
      "projectImage": "sketches/2026-08-23T22-53-14-a-peach-hibiscus-half-open-bud-fallen-pe/painting.png",
      "projectSource": "sketches/2026-08-23T22-53-14-a-peach-hibiscus-half-open-bud-fallen-pe/sketch.js"
    },
    {
      "attemptId": "2026-08-23T22-55-51-a-crow-on-a-telephone-wire-in-winter-fog",
      "status": "success",
      "round": "legacy-baseline",
      "prompt": "a crow on a telephone wire in winter fog, distant hills",
      "promptId": "crow-core-v1",
      "promptSpec": "legacy-unversioned",
      "provider": "not-recorded",
      "model": "deepseek-v4-flash",
      "medium": "ink",
      "paper": "cream",
      "seed": null,
      "canvas": {
        "width": 600,
        "height": 600
      },
      "image": "/images/model-painting-study/2026-08-23T22-55-51-a-crow-on-a-telephone-wire-in-winter-fog.png",
      "source": "/images/model-painting-study/2026-08-23T22-55-51-a-crow-on-a-telephone-wire-in-winter-fog.js.txt",
      "provenanceNote": "The legacy metadata recorded the model but not provider, protocol, seed, or exact system prompt.",
      "projectImage": "sketches/2026-08-23T22-55-51-a-crow-on-a-telephone-wire-in-winter-fog/painting.png",
      "projectSource": "sketches/2026-08-23T22-55-51-a-crow-on-a-telephone-wire-in-winter-fog/sketch.js"
    },
    {
      "attemptId": "2026-08-23T22-58-12-a-luna-moth-on-a-dark-windowsill-lamplig",
      "status": "success",
      "round": "legacy-baseline",
      "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
      "promptId": "luna-moth-core-v1",
      "promptSpec": "legacy-unversioned",
      "provider": "not-recorded",
      "model": "deepseek-v4-flash",
      "medium": "watercolor",
      "paper": "night",
      "seed": null,
      "canvas": {
        "width": 600,
        "height": 600
      },
      "image": "/images/model-painting-study/2026-08-23T22-58-12-a-luna-moth-on-a-dark-windowsill-lamplig.png",
      "source": "/images/model-painting-study/2026-08-23T22-58-12-a-luna-moth-on-a-dark-windowsill-lamplig.js.txt",
      "provenanceNote": "The legacy metadata recorded the model but not provider, protocol, seed, or exact system prompt.",
      "projectImage": "sketches/2026-08-23T22-58-12-a-luna-moth-on-a-dark-windowsill-lamplig/painting.png",
      "projectSource": "sketches/2026-08-23T22-58-12-a-luna-moth-on-a-dark-windowsill-lamplig/sketch.js"
    }
  ],
  "reviews": {
    "scale": "Eight editorial dimensions, each scored 0–5. These are subjective visual reviews, not benchmark-grade preference labels.",
    "dimensions": [
      "recognizability",
      "composition",
      "mediumFidelity",
      "palette",
      "detail",
      "artifactFreedom",
      "originality",
      "promptAdherence"
    ],
    "reviews": {
      "2026-08-23T22-53-14-a-peach-hibiscus-half-open-bud-fallen-pe": {
        "featured": false,
        "note": "Recognizable botanical structure, but the petals nearly disappear into the paper.",
        "scores": [
          3,
          3,
          4,
          3,
          2,
          4,
          4,
          4
        ]
      },
      "2026-08-23T22-55-51-a-crow-on-a-telephone-wire-in-winter-fog": {
        "featured": true,
        "highResAttemptId": "2026-08-24T00-28-23-17e31052-62af-473a-aa60-eee1764adfaf",
        "note": "The strongest early composition: bird, wire, and fog read immediately, though the anatomy is simplified.",
        "scores": [
          4,
          5,
          4,
          4,
          4,
          4,
          4,
          5
        ]
      },
      "2026-08-23T22-58-12-a-luna-moth-on-a-dark-windowsill-lamplig": {
        "featured": true,
        "highResAttemptId": "2026-08-24T00-23-36-405e2723-f9c5-4f8a-af67-e4632d24d17c",
        "note": "Atmospheric and coherent; the dark values obscure some wing detail.",
        "scores": [
          4,
          4,
          4,
          4,
          3,
          4,
          4,
          4
        ]
      },
      "2026-08-24T00-02-58-d1794f86-5fc2-4031-b3bb-b7fa5d6a6604": {
        "featured": false,
        "note": "The subject is too small and weak against the wire and distant layers.",
        "scores": [
          2,
          2,
          3,
          2,
          2,
          4,
          2,
          3
        ]
      },
      "2026-08-24T00-03-01-cf956b7e-505b-4e6e-ab7e-721e8512dbf5": {
        "featured": false,
        "note": "The round body reads more like a generic bird icon than a crow.",
        "scores": [
          2,
          2,
          3,
          2,
          2,
          4,
          3,
          2
        ]
      },
      "2026-08-24T00-14-58-b9378101-6f68-4b6a-b961-801e279536b7": {
        "featured": false,
        "note": "The wire and hills read, but the bird collapses into disconnected pale forms.",
        "scores": [
          1,
          3,
          3,
          3,
          2,
          3,
          3,
          3
        ]
      },
      "2026-08-24T00-15-09-89f086e0-c998-46cf-9c3f-553ff9280626": {
        "featured": false,
        "note": "The structure is present, but tonal contrast is too low for a finished focal image.",
        "scores": [
          3,
          3,
          3,
          2,
          2,
          4,
          3,
          4
        ]
      },
      "2026-08-24T00-15-12-8be32637-6390-42b9-9037-cfa9533cb2bb": {
        "featured": false,
        "note": "An airy full-plant study with graceful spacing, still much too pale.",
        "scores": [
          4,
          4,
          4,
          3,
          3,
          4,
          4,
          4
        ]
      },
      "2026-08-24T00-15-32-d7d6f73d-dc57-4a4b-bca9-0b6e710feef3": {
        "featured": false,
        "note": "Clear hierarchy and weather, but the focal bird remains undersized.",
        "scores": [
          3,
          3,
          4,
          3,
          3,
          4,
          3,
          4
        ]
      },
      "2026-08-24T00-15-49-1752d0e1-22de-4fbf-ac50-012695528ee8": {
        "featured": false,
        "note": "Stamen and leaf marks float without a convincing bloom silhouette.",
        "scores": [
          1,
          2,
          3,
          3,
          2,
          3,
          3,
          2
        ]
      },
      "2026-08-24T00-16-04-df5a7c43-66ff-460e-b535-353ed9811900": {
        "featured": true,
        "note": "Strong silhouette, windowsill, and night mood; one of the clearest moth results.",
        "scores": [
          4,
          4,
          4,
          4,
          4,
          4,
          4,
          4
        ]
      },
      "2026-08-24T00-16-19-c477f4c0-abd6-4421-8649-426f622d4c6e": {
        "featured": false,
        "note": "Large and dramatic but diagram-like; circular geometry overwhelms the moth anatomy.",
        "scores": [
          2,
          3,
          3,
          3,
          2,
          2,
          3,
          2
        ]
      },
      "2026-08-24T00-16-41-471576e8-b214-46dc-88cb-123672fd9d7a": {
        "featured": false,
        "note": "A coherent botanical-night abstraction whose wing anatomy remains ambiguous.",
        "scores": [
          3,
          4,
          4,
          4,
          3,
          3,
          4,
          3
        ]
      },
      "2026-08-24T00-18-23-68a712ee-f85d-4af7-89ab-b3e352190762": {
        "featured": false,
        "note": "A legible flower and stem, but simplified and spare.",
        "scores": [
          4,
          3,
          3,
          3,
          2,
          4,
          3,
          3
        ]
      },
      "2026-08-24T00-19-01-78b33177-43b8-4095-9d2a-7917716ced61": {
        "featured": true,
        "highResAttemptId": "2026-08-24T00-27-25-fd19c191-f0d8-459e-94d2-00a3e6b3779e",
        "note": "A clear centered moth with strong contrast; the environment is sparse.",
        "scores": [
          4,
          3,
          3,
          3,
          3,
          4,
          3,
          3
        ]
      },
      "2026-08-24T00-22-03-6b173950-6839-49ba-907e-b7270bdb3853": {
        "featured": true,
        "highResAttemptId": "2026-08-24T00-27-12-403acaab-a3c5-43bf-9479-46da6043e6a0",
        "note": "The blueprint produces Inkling's strongest result: focal throat, layered petals, and a coherent stem.",
        "scores": [
          4,
          4,
          4,
          4,
          3,
          4,
          4,
          4
        ]
      },
      "2026-08-24T00-22-11-74a04cfa-3a90-4373-b674-fcfa57973ddc": {
        "featured": false,
        "note": "The blueprint adds a bud and full plant, but the bloom remains weakly defined.",
        "scores": [
          3,
          3,
          3,
          3,
          2,
          4,
          3,
          4
        ]
      },
      "2026-08-24T00-22-33-3a0573d7-b695-4cbd-8af4-580e9e57e653": {
        "featured": false,
        "note": "Scale and hierarchy improve, but disconnected polygonal anatomy keeps the bird illustrative.",
        "scores": [
          3,
          4,
          3,
          3,
          2,
          3,
          3,
          3
        ]
      },
      "2026-08-24T00-23-30-aa1fd085-ed16-4dc0-adcd-7fd3d000ba72": {
        "featured": false,
        "note": "Bilateral structure improves, but circular motifs violate the composition direction.",
        "scores": [
          3,
          3,
          3,
          3,
          2,
          2,
          3,
          2
        ]
      },
      "2026-08-24T00-23-33-756b040e-12bc-42f0-9b13-133857f8c2e7": {
        "featured": true,
        "highResAttemptId": "2026-08-24T00-27-18-4567d058-915e-4ccc-ab69-503a4511205d",
        "note": "A large readable bird, wire, and fog layers; the silhouette resembles waterfowl more than a crow.",
        "scores": [
          4,
          5,
          4,
          4,
          4,
          4,
          4,
          4
        ]
      },
      "2026-08-24T00-24-43-0348811a-32a7-4b6e-9995-5b05cacb706f": {
        "featured": true,
        "highResAttemptId": "2026-08-24T00-27-37-ee9f23b2-4618-4753-babb-f0dc01c39021",
        "note": "A strong final night composition with clear body, wings, sill, and restrained garden marks.",
        "scores": [
          4,
          4,
          4,
          4,
          3,
          4,
          4,
          4
        ]
      }
    }
  },
  "promptRequests": [
    {
      "id": "6377164c7fcc58c9",
      "provider": "opencode-go",
      "model": "grok-4.5",
      "protocol": "responses",
      "system": "You write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nMostly stroke: HB, 2B, pen. Pale wash only for stains and shadow. High contrast. Dry, broken lines. Leave large untouched paper.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add 2–5 faint stains or edge darkening so it reads as paper, not a UI canvas.\n\nTASTE\n- One clear subject, large on the page. Not a tiny icon in the middle.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye.",
      "user": "Paint this as a finished ink picture:\na crow on a telephone wire in winter fog, distant hills\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1702) and noiseSeed(1702) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "6f15f6f7ee343034",
      "provider": "opencode-go",
      "model": "gpt-5.6-luna",
      "protocol": "responses",
      "system": "You write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nMostly stroke: HB, 2B, pen. Pale wash only for stains and shadow. High contrast. Dry, broken lines. Leave large untouched paper.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add 2–5 faint stains or edge darkening so it reads as paper, not a UI canvas.\n\nTASTE\n- One clear subject, large on the page. Not a tiny icon in the middle.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye.",
      "user": "Paint this as a finished ink picture:\na crow on a telephone wire in winter fog, distant hills\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1702) and noiseSeed(1702) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "124bb7ff9184818f",
      "provider": "openrouter",
      "model": "thinkingmachines/inkling",
      "protocol": "chat",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nHigh contrast with dry, broken HB, 2B, and pen lines. Give the subject a decisive dark mass using fill opacity 180–245; reserve pale wash for fog, stains, and shadow. Leave large untouched paper.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished ink picture:\na crow on a telephone wire in winter fog, distant hills\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1702) and noiseSeed(1702) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "61237709ff073df3",
      "provider": "opencode-go",
      "model": "gpt-5.6-luna",
      "protocol": "responses",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1701) and noiseSeed(1701) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "15e20f913721250f",
      "provider": "opencode-go",
      "model": "grok-4.5",
      "protocol": "responses",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1701) and noiseSeed(1701) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "ea28cea4cdec6dfd",
      "provider": "opencode-go",
      "model": "qwen3.8-max",
      "protocol": "messages",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nHigh contrast with dry, broken HB, 2B, and pen lines. Give the subject a decisive dark mass using fill opacity 180–245; reserve pale wash for fog, stains, and shadow. Leave large untouched paper.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished ink picture:\na crow on a telephone wire in winter fog, distant hills\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1702) and noiseSeed(1702) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "a2c9c1edfa1e1798",
      "provider": "openrouter",
      "model": "thinkingmachines/inkling",
      "protocol": "chat",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1701) and noiseSeed(1701) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "2c211278a175c473",
      "provider": "opencode-go",
      "model": "gpt-5.6-luna",
      "protocol": "responses",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#0c120e\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #0c120e (night). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na luna moth on a dark windowsill, lamplight, night garden beyond\n\nPaper: night (#0c120e)\nCanvas: 600x600\nCall randomSeed(1703) and noiseSeed(1703) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "40a642d65e254a03",
      "provider": "openrouter",
      "model": "thinkingmachines/inkling",
      "protocol": "chat",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#0c120e\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #0c120e (night). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na luna moth on a dark windowsill, lamplight, night garden beyond\n\nPaper: night (#0c120e)\nCanvas: 600x600\nCall randomSeed(1703) and noiseSeed(1703) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "d5bd757db3ece6a4",
      "provider": "opencode-go",
      "model": "grok-4.5",
      "protocol": "responses",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#0c120e\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #0c120e (night). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na luna moth on a dark windowsill, lamplight, night garden beyond\n\nPaper: night (#0c120e)\nCanvas: 600x600\nCall randomSeed(1703) and noiseSeed(1703) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "49500c3845a6c972",
      "provider": "opencode-go",
      "model": "qwen3.8-max",
      "protocol": "messages",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1701) and noiseSeed(1701) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "1976a3111b09796b",
      "provider": "opencode-go",
      "model": "qwen3.8-max",
      "protocol": "messages",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#0c120e\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #0c120e (night). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na luna moth on a dark windowsill, lamplight, night garden beyond\n\nPaper: night (#0c120e)\nCanvas: 600x600\nCall randomSeed(1703) and noiseSeed(1703) at the start of setup.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "857b0cd453480173",
      "provider": "openrouter",
      "model": "thinkingmachines/inkling",
      "protocol": "chat",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1701) and noiseSeed(1701) at the start of setup.\n\nSHARED COMPOSITION BLUEPRINT\nPaint one naturalistic hibiscus bloom spanning approximately x=110..475 and y=85..425. Use five overlapping, unequal 7–12-vertex petal contours around a throat near (300, 270); do not use circles for petals. Add one half-open bud near (455, 175), a curved stem descending toward (250, 560), two leaves, and two or three fallen petals in the lower-left third. Put the darkest peach-red and green marks at the throat, stamen, and stem junction. Keep tea stains extremely faint.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "5ffec65a2f37d9e5",
      "provider": "opencode-go",
      "model": "grok-4.5",
      "protocol": "responses",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1701) and noiseSeed(1701) at the start of setup.\n\nSHARED COMPOSITION BLUEPRINT\nPaint one naturalistic hibiscus bloom spanning approximately x=110..475 and y=85..425. Use five overlapping, unequal 7–12-vertex petal contours around a throat near (300, 270); do not use circles for petals. Add one half-open bud near (455, 175), a curved stem descending toward (250, 560), two leaves, and two or three fallen petals in the lower-left third. Put the darkest peach-red and green marks at the throat, stamen, and stem junction. Keep tea stains extremely faint.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "54f6c891093fbae8",
      "provider": "openrouter",
      "model": "thinkingmachines/inkling",
      "protocol": "chat",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nHigh contrast with dry, broken HB, 2B, and pen lines. Give the subject a decisive dark mass using fill opacity 180–245; reserve pale wash for fog, stains, and shadow. Leave large untouched paper.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished ink picture:\na crow on a telephone wire in winter fog, distant hills\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1702) and noiseSeed(1702) at the start of setup.\n\nSHARED COMPOSITION BLUEPRINT\nPaint one large, readable side-view crow spanning approximately x=150..440 and y=135..350, facing left. Build distinct closed contours for head, beak, chest, folded wing, belly, and tail; do not use circles for the body. Run the telephone wire across y=355 and place quiet fog-softened hills only in the lower third. The crow must be the darkest and crispest mass in the image; keep the full beak and tail on-canvas.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "909e8d589723119b",
      "provider": "openrouter",
      "model": "thinkingmachines/inkling",
      "protocol": "chat",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#0c120e\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #0c120e (night). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na luna moth on a dark windowsill, lamplight, night garden beyond\n\nPaper: night (#0c120e)\nCanvas: 600x600\nCall randomSeed(1703) and noiseSeed(1703) at the start of setup.\n\nSHARED COMPOSITION BLUEPRINT\nPaint one luna moth with wings spanning approximately x=90..510 and y=100..445 and a narrow body near x=285..315. Use separate closed contours for two forewings and two hindwings, with hindwing tails extending toward y=470; symmetry may be loose but anatomy must read. Place a soft lamplight halo in the upper-right and a dark windowsill across y=510, with only a few quiet garden marks beyond. Keep wing veins sparse and organic. Do not add arbitrary polygons, framing boxes, or circular diagrams.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "6f96491d8b4be496",
      "provider": "opencode-go",
      "model": "grok-4.5",
      "protocol": "responses",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#f4e8c1\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nHigh contrast with dry, broken HB, 2B, and pen lines. Give the subject a decisive dark mass using fill opacity 180–245; reserve pale wash for fog, stains, and shadow. Leave large untouched paper.\n\nPAPER\nGround colour is #f4e8c1 (cream). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished ink picture:\na crow on a telephone wire in winter fog, distant hills\n\nPaper: cream (#f4e8c1)\nCanvas: 600x600\nCall randomSeed(1702) and noiseSeed(1702) at the start of setup.\n\nSHARED COMPOSITION BLUEPRINT\nPaint one large, readable side-view crow spanning approximately x=150..440 and y=135..350, facing left. Build distinct closed contours for head, beak, chest, folded wing, belly, and tail; do not use circles for the body. Run the telephone wire across y=355 and place quiet fog-softened hills only in the lower third. The crow must be the darkest and crispest mass in the image; keep the full beak and tail on-canvas.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    },
    {
      "id": "b56cf4588d60b93d",
      "provider": "opencode-go",
      "model": "grok-4.5",
      "protocol": "responses",
      "system": "PROMPT SPEC: taste-v2\n\nYou write complete p5.js sketches that PAINT with the p5.brush library.\n\nReturn ONLY JavaScript source for sketch.js. No markdown fences. No explanation.\n\nREQUIRED SHAPE (copy this structure):\nasync function setup() {\n  createCanvas(600, 600, WEBGL);\n  angleMode(DEGREES);\n  brush.scaleBrushes(3);\n  noLoop();\n}\nfunction draw() {\n  translate(-width / 2, -height / 2);\n  background(\"#0c120e\");\n  // painting\n}\n\nHARD RULES\n- Canvas MUST be WEBGL. WEBGL origin is the center; always translate(-width/2, -height/2) before drawing.\n- That translation changes the visible drawing area to x=0..600, y=0..600. Use those top-left coordinates for every visible mark. Negative coordinates are off-canvas.\n- Paint ONLY with brush.* listed below. Native p5 drawing (ellipse, triangle, line, rect, fill, stroke, bezier, beginShape without brush.) is forbidden for the picture.\n- background(), push(), pop(), translate(), rotate(), random(), noise(), lerp(), map(), dist(), sin(), cos(), color(), lerpColor() are allowed.\n- Do not invent APIs. If it is not on the allowlist, it does not exist.\n- Do not load images, fonts, or files.\n- Do not animate. Call noLoop() in setup.\n- Do not write HTML, markdown, or the string </script>.\n- Every beginShape() must have at least 3 vertex() calls and an endShape().\n- Close filled shapes with brush.endShape(true). Use brush.endShape(false) only after brush.noFill().\n- Target 80–220 lines. Dense marks, not verbose comments.\n\nALLOWLIST — stroke\n- brush.set(name, color, weight)\n- brush.pick(name)\n- brush.stroke(color)\n- brush.strokeWeight(weight)\n- brush.noStroke()\n- brush.line(x1, y1, x2, y2)\n- brush.flowLine(x, y, length, dir)\n\nALLOWLIST — watercolor fill\n- brush.fill(color, opacity)          // opacity 0–255\n- brush.noFill()\n- brush.fillBleed(strength, \"in\"|\"out\")  // strength 0–1\n- brush.fillTexture(texture, border)     // both 0–1\n- brush.circle(x, y, radius, irregularity?)\n- brush.rect(x, y, w, h, \"corner\"|\"center\")\n- brush.beginShape(curvature)\n- brush.vertex(x, y)\n- brush.endShape(closeBoolean)\n\nALLOWLIST — hatch / field\n- brush.hatch(dist, angle, { rand })\n- brush.hatchStyle(name, color, weight)\n- brush.noHatch()\n- brush.field(\"hand\"|\"curved\"|\"waves\"|\"seabed\"|\"spiral\")\n- brush.noField()\n\nBRUSH NAMES: \"2B\", \"HB\", \"2H\", \"pen\", \"rotring\", \"marker\", \"charcoal\"\nCOLOURS: hex strings like \"#c06c5a\"\n\nMEDIUM\nTransparent overlapping washes. Use opacity 45–110 for focal glazes and 12–40 only for atmosphere. bleed 0.12–0.45. Paper must show through. Soft feathered edges. Build the subject from 2–4 stacked glazes, not a hard outline.\n\nPAPER\nGround colour is #0c120e (night). Start with background() of that colour. Add at most 1–3 faint stains inside the visible canvas. Do not draw a decorative border or four-corner vignette.\n\nTASTE\n- One clear subject, large on the page: the main silhouette should span roughly 40–70% of the canvas width or height, with its focal point inside the central 80%.\n- Make the subject readable at thumbnail size. Establish one decisive silhouette before adding texture.\n- Build a clear value hierarchy: the darkest dark and crispest edge belong near the focal subject; atmosphere and background stay quieter.\n- Prefer 6–16 deliberately placed contour vertices over primitive icons. Use randomness for texture, never for the primary anatomy or silhouette.\n- Use three spatial layers at most: quiet ground/atmosphere, dominant subject, and a small number of accents. Avoid scattered filler marks.\n- Overlap 4–12 organic shapes. Petals, leaves, hills, cloth, birds — built from beginShape vertices, never a perfect regular polygon unless the subject is geometric.\n- Avoid clip-art: no five identical rotated petals as the whole picture, no emoji faces, no symmetric logo flowers.\n- Limited palette: 3–5 colours plus paper.\n- Leave breathing room. Do not fill every pixel.\n- If the subject is a plant, include stem/sepals/stain/shadow, not only the bloom.\n- Irregularity: vary vertex positions, use circle(..., 0.15–0.5), hatch with rand.\n- Composition: subject off dead-center is better than bullseye, but keep the whole focal silhouette on-canvas.\n- Restraint: stop when the image reads. Fewer confident masses are better than many pale, unrelated marks.",
      "user": "Paint this as a finished watercolor picture:\na luna moth on a dark windowsill, lamplight, night garden beyond\n\nPaper: night (#0c120e)\nCanvas: 600x600\nCall randomSeed(1703) and noiseSeed(1703) at the start of setup.\n\nSHARED COMPOSITION BLUEPRINT\nPaint one luna moth with wings spanning approximately x=90..510 and y=100..445 and a narrow body near x=285..315. Use separate closed contours for two forewings and two hindwings, with hindwing tails extending toward y=470; symmetry may be loose but anatomy must read. Place a soft lamplight halo in the upper-right and a dark windowsill across y=510, with only a few quiet garden marks beyond. Keep wing veins sparse and organic. Do not add arbitrary polygons, framing boxes, or circular diagrams.\n\nOutput only the complete sketch.js source.",
      "maxTokens": 8192,
      "temperature": 1,
      "images": 0
    }
  ],
  "attempts": [
    {
      "attemptId": "2026-08-24T00-02-58-d1794f86-5fc2-4031-b3bb-b7fa5d6a6604",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-02-58-d1794f86-5fc2-4031-b3bb-b7fa5d6a6604",
        "createdAt": "2026-08-24T00:02:58.655Z",
        "prompt": "a crow on a telephone wire in winter fog, distant hills",
        "promptId": "crow-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "provider": "opencode-go",
        "model": "grok-4.5",
        "medium": "ink",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1702,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "6377164c7fcc58c9",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "grok-4.5",
          "protocol": "responses",
          "latencyMs": 59690,
          "usage": {
            "input_tokens": 1252,
            "output_tokens": 4033,
            "total_tokens": 5285,
            "input_tokens_details": {
              "cached_tokens": 128
            },
            "output_tokens_details": {
              "reasoning_tokens": 140
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-02-58-d1794f86-5fc2-4031-b3bb-b7fa5d6a6604/painting.png",
        "projectSource": "sketches/2026-08-24T00-02-58-d1794f86-5fc2-4031-b3bb-b7fa5d6a6604/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-02-58-d1794f86-5fc2-4031-b3bb-b7fa5d6a6604.png",
        "source": "/images/model-painting-study/2026-08-24T00-02-58-d1794f86-5fc2-4031-b3bb-b7fa5d6a6604.js.txt",
        "stats": {
          "unique": 259,
          "meanLuma": 228.10376814236372,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1
        },
        "hashes": {
          "code": "692930d7f5773a0295c90ae234bf4fc11b08baaa2c58caee8b824f64a82e7e19",
          "png": "c26b5c0d1c1a6a66ae9f672f003e762fd3b1659dbc6afb0e97ba484fc9555f49",
          "raw": "692930d7f5773a0295c90ae234bf4fc11b08baaa2c58caee8b824f64a82e7e19"
        },
        "latencyMs": 59690,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1252,
              "output_tokens": 4033,
              "total_tokens": 5285,
              "input_tokens_details": {
                "cached_tokens": 128
              },
              "output_tokens_details": {
                "reasoning_tokens": 140
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "grok-4.5",
            "protocol": "responses",
            "latencyMs": 59690
          }
        ]
      },
      "failure": null,
      "eventCount": 2,
      "lastEvent": {
        "at": "2026-08-24T00:04:07.980Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 259,
          "meanLuma": 228.10376814236372,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-03-01-cf956b7e-505b-4e6e-ab7e-721e8512dbf5",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-03-01-cf956b7e-505b-4e6e-ab7e-721e8512dbf5",
        "createdAt": "2026-08-24T00:03:01.089Z",
        "prompt": "a crow on a telephone wire in winter fog, distant hills",
        "promptId": "crow-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "provider": "opencode-go",
        "model": "gpt-5.6-luna",
        "medium": "ink",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1702,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "6f15f6f7ee343034",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "gpt-5.6-luna",
          "protocol": "responses",
          "latencyMs": 22047,
          "usage": {
            "input_tokens": 918,
            "output_tokens": 2850,
            "total_tokens": 3768,
            "input_tokens_details": {
              "cached_tokens": 0,
              "cache_write_tokens": 0
            },
            "output_tokens_details": {
              "reasoning_tokens": 794
            }
          }
        },
        {
          "stage": "repair",
          "provider": "opencode-go",
          "model": "gpt-5.6-luna",
          "protocol": "responses",
          "latencyMs": 12217,
          "usage": {
            "input_tokens": 3013,
            "output_tokens": 2212,
            "total_tokens": 5225,
            "input_tokens_details": {
              "cached_tokens": 0,
              "cache_write_tokens": 3010
            },
            "output_tokens_details": {
              "reasoning_tokens": 171
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-03-01-cf956b7e-505b-4e6e-ab7e-721e8512dbf5/painting.png",
        "projectSource": "sketches/2026-08-24T00-03-01-cf956b7e-505b-4e6e-ab7e-721e8512dbf5/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-03-01-cf956b7e-505b-4e6e-ab7e-721e8512dbf5.png",
        "source": "/images/model-painting-study/2026-08-24T00-03-01-cf956b7e-505b-4e6e-ab7e-721e8512dbf5.js.txt",
        "stats": {
          "unique": 286,
          "meanLuma": 224.7694973090307,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1
        },
        "hashes": {
          "code": "5f5db7664ec8733531e2080d36e309b861218afa9a6107c7d1940b7c0a05f2a5",
          "png": "81371aadcf41c248ca6987ac8f8742d96187d94f4ad712cce89ef1db5bbd6c7a",
          "raw": "07a2cb30cb994a0425d27e7425d5dd728ee9617aa62f70faeb29c0ade7e46f53"
        },
        "latencyMs": 34264,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 918,
              "output_tokens": 2850,
              "total_tokens": 3768,
              "input_tokens_details": {
                "cached_tokens": 0,
                "cache_write_tokens": 0
              },
              "output_tokens_details": {
                "reasoning_tokens": 794
              }
            }
          },
          {
            "stage": "repair",
            "usage": {
              "input_tokens": 3013,
              "output_tokens": 2212,
              "total_tokens": 5225,
              "input_tokens_details": {
                "cached_tokens": 0,
                "cache_write_tokens": 3010
              },
              "output_tokens_details": {
                "reasoning_tokens": 171
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "gpt-5.6-luna",
            "protocol": "responses",
            "latencyMs": 22047
          },
          {
            "stage": "repair",
            "provider": "opencode-go",
            "model": "gpt-5.6-luna",
            "protocol": "responses",
            "latencyMs": 12217
          }
        ]
      },
      "failure": null,
      "eventCount": 4,
      "lastEvent": {
        "at": "2026-08-24T00:03:52.304Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 286,
          "meanLuma": 224.7694973090307,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-14-58-b9378101-6f68-4b6a-b961-801e279536b7",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-14-58-b9378101-6f68-4b6a-b961-801e279536b7",
        "createdAt": "2026-08-24T00:14:58.831Z",
        "prompt": "a crow on a telephone wire in winter fog, distant hills",
        "promptId": "crow-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "openrouter",
        "model": "thinkingmachines/inkling",
        "medium": "ink",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1702,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "124bb7ff9184818f",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "openrouter",
          "model": "thinkingmachines/inkling",
          "protocol": "chat",
          "latencyMs": 8800,
          "usage": {
            "prompt_tokens": 1171,
            "completion_tokens": 1780,
            "total_tokens": 2951,
            "cost": 0.00832145,
            "is_byok": false,
            "prompt_tokens_details": {
              "cached_tokens": 0,
              "cache_write_tokens": 0,
              "audio_tokens": 0,
              "video_tokens": 0
            },
            "cost_details": {
              "upstream_inference_cost": 0.00832145,
              "upstream_inference_prompt_cost": 0.00111245,
              "upstream_inference_completions_cost": 0.007209
            },
            "completion_tokens_details": {
              "reasoning_tokens": 575,
              "image_tokens": 0,
              "audio_tokens": 0
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-14-58-b9378101-6f68-4b6a-b961-801e279536b7/painting.png",
        "projectSource": "sketches/2026-08-24T00-14-58-b9378101-6f68-4b6a-b961-801e279536b7/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-14-58-b9378101-6f68-4b6a-b961-801e279536b7.png",
        "source": "/images/model-painting-study/2026-08-24T00-14-58-b9378101-6f68-4b6a-b961-801e279536b7.js.txt",
        "stats": {
          "unique": 192,
          "meanLuma": 227.91448116319665,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "1e0f2ce664be0773d90154a04e3ba82af07d76128d7356846c8dbc8a72c9edf1",
          "png": "ddfceac0d23a79949b659f0c55bb505f0f609e6fd2ff25f212936986ff896f92",
          "raw": "1e0f2ce664be0773d90154a04e3ba82af07d76128d7356846c8dbc8a72c9edf1"
        },
        "latencyMs": 8800,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "prompt_tokens": 1171,
              "completion_tokens": 1780,
              "total_tokens": 2951,
              "cost": 0.00832145,
              "is_byok": false,
              "prompt_tokens_details": {
                "cached_tokens": 0,
                "cache_write_tokens": 0,
                "audio_tokens": 0,
                "video_tokens": 0
              },
              "cost_details": {
                "upstream_inference_cost": 0.00832145,
                "upstream_inference_prompt_cost": 0.00111245,
                "upstream_inference_completions_cost": 0.007209
              },
              "completion_tokens_details": {
                "reasoning_tokens": 575,
                "image_tokens": 0,
                "audio_tokens": 0
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "openrouter",
            "model": "thinkingmachines/inkling",
            "protocol": "chat",
            "latencyMs": 8800
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.041Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-15-09-89f086e0-c998-46cf-9c3f-553ff9280626",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-15-09-89f086e0-c998-46cf-9c3f-553ff9280626",
        "createdAt": "2026-08-24T00:15:09.505Z",
        "prompt": "a peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper",
        "promptId": "hibiscus-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "opencode-go",
        "model": "gpt-5.6-luna",
        "medium": "watercolor",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1701,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "61237709ff073df3",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "gpt-5.6-luna",
          "protocol": "responses",
          "latencyMs": 13270,
          "usage": {
            "input_tokens": 1179,
            "output_tokens": 1469,
            "total_tokens": 2648,
            "input_tokens_details": {
              "cached_tokens": 0,
              "cache_write_tokens": 1176
            },
            "output_tokens_details": {
              "reasoning_tokens": 932
            }
          }
        },
        {
          "stage": "repair",
          "provider": "opencode-go",
          "model": "gpt-5.6-luna",
          "protocol": "responses",
          "latencyMs": 20000,
          "usage": {
            "input_tokens": 1725,
            "output_tokens": 2520,
            "total_tokens": 4245,
            "input_tokens_details": {
              "cached_tokens": 0,
              "cache_write_tokens": 1722
            },
            "output_tokens_details": {
              "reasoning_tokens": 369
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-15-09-89f086e0-c998-46cf-9c3f-553ff9280626/painting.png",
        "projectSource": "sketches/2026-08-24T00-15-09-89f086e0-c998-46cf-9c3f-553ff9280626/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-15-09-89f086e0-c998-46cf-9c3f-553ff9280626.png",
        "source": "/images/model-painting-study/2026-08-24T00-15-09-89f086e0-c998-46cf-9c3f-553ff9280626.js.txt",
        "stats": {
          "unique": 92,
          "meanLuma": 231.00714583333698,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "9f220d328ab0f3a839e58afd1c63b878d96df4b63730fa92f60182ddb26e4a63",
          "png": "2dee60d37015fc73829b5070c1e2de6e04f51eb7e7188ab54ddd5f68668a064a",
          "raw": "0ac9876c4b7cc3f2567693bc3bfb52f44e9cdb5e20ae23d7e54a74046bb14abb"
        },
        "latencyMs": 33270,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1179,
              "output_tokens": 1469,
              "total_tokens": 2648,
              "input_tokens_details": {
                "cached_tokens": 0,
                "cache_write_tokens": 1176
              },
              "output_tokens_details": {
                "reasoning_tokens": 932
              }
            }
          },
          {
            "stage": "repair",
            "usage": {
              "input_tokens": 1725,
              "output_tokens": 2520,
              "total_tokens": 4245,
              "input_tokens_details": {
                "cached_tokens": 0,
                "cache_write_tokens": 1722
              },
              "output_tokens_details": {
                "reasoning_tokens": 369
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "gpt-5.6-luna",
            "protocol": "responses",
            "latencyMs": 13270
          },
          {
            "stage": "repair",
            "provider": "opencode-go",
            "model": "gpt-5.6-luna",
            "protocol": "responses",
            "latencyMs": 20000
          }
        ]
      },
      "failure": null,
      "eventCount": 5,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.042Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-15-12-8be32637-6390-42b9-9037-cfa9533cb2bb",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-15-12-8be32637-6390-42b9-9037-cfa9533cb2bb",
        "createdAt": "2026-08-24T00:15:12.453Z",
        "prompt": "a peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper",
        "promptId": "hibiscus-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "opencode-go",
        "model": "grok-4.5",
        "medium": "watercolor",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1701,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "15e20f913721250f",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "grok-4.5",
          "protocol": "responses",
          "latencyMs": 50523,
          "usage": {
            "input_tokens": 1514,
            "output_tokens": 4135,
            "total_tokens": 5649,
            "input_tokens_details": {
              "cached_tokens": 128
            },
            "output_tokens_details": {
              "reasoning_tokens": 162
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-15-12-8be32637-6390-42b9-9037-cfa9533cb2bb/painting.png",
        "projectSource": "sketches/2026-08-24T00-15-12-8be32637-6390-42b9-9037-cfa9533cb2bb/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-15-12-8be32637-6390-42b9-9037-cfa9533cb2bb.png",
        "source": "/images/model-painting-study/2026-08-24T00-15-12-8be32637-6390-42b9-9037-cfa9533cb2bb.js.txt",
        "stats": {
          "unique": 258,
          "meanLuma": 229.3542522569475,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "9a41659dc0e646717fb96fe320647cd7363d15a45d3c7380e250b3429bac0e9b",
          "png": "d07a27e6220f94834301bd50f587126563e01d3fea6336adb009e97ce2562fd9",
          "raw": "9a41659dc0e646717fb96fe320647cd7363d15a45d3c7380e250b3429bac0e9b"
        },
        "latencyMs": 50523,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1514,
              "output_tokens": 4135,
              "total_tokens": 5649,
              "input_tokens_details": {
                "cached_tokens": 128
              },
              "output_tokens_details": {
                "reasoning_tokens": 162
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "grok-4.5",
            "protocol": "responses",
            "latencyMs": 50523
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.042Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-15-32-d7d6f73d-dc57-4a4b-bca9-0b6e710feef3",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-15-32-d7d6f73d-dc57-4a4b-bca9-0b6e710feef3",
        "createdAt": "2026-08-24T00:15:32.273Z",
        "prompt": "a crow on a telephone wire in winter fog, distant hills",
        "promptId": "crow-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "opencode-go",
        "model": "qwen3.8-max",
        "medium": "ink",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1702,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "ea28cea4cdec6dfd",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "qwen3.8-max",
          "protocol": "messages",
          "latencyMs": 29546,
          "usage": {
            "input_tokens": 1261,
            "output_tokens": 2214,
            "cache_creation_input_tokens": 0,
            "cache_read_input_tokens": 0
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-15-32-d7d6f73d-dc57-4a4b-bca9-0b6e710feef3/painting.png",
        "projectSource": "sketches/2026-08-24T00-15-32-d7d6f73d-dc57-4a4b-bca9-0b6e710feef3/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-15-32-d7d6f73d-dc57-4a4b-bca9-0b6e710feef3.png",
        "source": "/images/model-painting-study/2026-08-24T00-15-32-d7d6f73d-dc57-4a4b-bca9-0b6e710feef3.js.txt",
        "stats": {
          "unique": 343,
          "meanLuma": 222.18838203125318,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "67b199d8e5c4dc387ff0ec65a57f4192443b769cb798ec1c2975ffcf66e6c3b0",
          "png": "a657ad2768b96bda5bc8e38f76157dbc049100dc77dc57a1b169bc61670254d8",
          "raw": "67b199d8e5c4dc387ff0ec65a57f4192443b769cb798ec1c2975ffcf66e6c3b0"
        },
        "latencyMs": 29546,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1261,
              "output_tokens": 2214,
              "cache_creation_input_tokens": 0,
              "cache_read_input_tokens": 0
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "qwen3.8-max",
            "protocol": "messages",
            "latencyMs": 29546
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.044Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-15-49-1752d0e1-22de-4fbf-ac50-012695528ee8",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-15-49-1752d0e1-22de-4fbf-ac50-012695528ee8",
        "createdAt": "2026-08-24T00:15:49.652Z",
        "prompt": "a peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper",
        "promptId": "hibiscus-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "openrouter",
        "model": "thinkingmachines/inkling",
        "medium": "watercolor",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1701,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "a2c9c1edfa1e1798",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "openrouter",
          "model": "thinkingmachines/inkling",
          "protocol": "chat",
          "latencyMs": 9333,
          "usage": {
            "prompt_tokens": 1190,
            "completion_tokens": 1961,
            "total_tokens": 3151,
            "cost": 0.00907255,
            "is_byok": false,
            "prompt_tokens_details": {
              "cached_tokens": 0,
              "cache_write_tokens": 0,
              "audio_tokens": 0,
              "video_tokens": 0
            },
            "cost_details": {
              "upstream_inference_cost": 0.00907255,
              "upstream_inference_prompt_cost": 0.0011305,
              "upstream_inference_completions_cost": 0.00794205
            },
            "completion_tokens_details": {
              "reasoning_tokens": 837,
              "image_tokens": 0,
              "audio_tokens": 0
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-15-49-1752d0e1-22de-4fbf-ac50-012695528ee8/painting.png",
        "projectSource": "sketches/2026-08-24T00-15-49-1752d0e1-22de-4fbf-ac50-012695528ee8/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-15-49-1752d0e1-22de-4fbf-ac50-012695528ee8.png",
        "source": "/images/model-painting-study/2026-08-24T00-15-49-1752d0e1-22de-4fbf-ac50-012695528ee8.js.txt",
        "stats": {
          "unique": 151,
          "meanLuma": 228.69899383680917,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "a0896476e4c17cd7d080aa60e2d60b0bacf12b815a742f5637293812d43913df",
          "png": "ab8a5531317670282fd0909d9c73e30ec118ea0d0bba95879031697ac14f3c6a",
          "raw": "a0896476e4c17cd7d080aa60e2d60b0bacf12b815a742f5637293812d43913df"
        },
        "latencyMs": 9333,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "prompt_tokens": 1190,
              "completion_tokens": 1961,
              "total_tokens": 3151,
              "cost": 0.00907255,
              "is_byok": false,
              "prompt_tokens_details": {
                "cached_tokens": 0,
                "cache_write_tokens": 0,
                "audio_tokens": 0,
                "video_tokens": 0
              },
              "cost_details": {
                "upstream_inference_cost": 0.00907255,
                "upstream_inference_prompt_cost": 0.0011305,
                "upstream_inference_completions_cost": 0.00794205
              },
              "completion_tokens_details": {
                "reasoning_tokens": 837,
                "image_tokens": 0,
                "audio_tokens": 0
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "openrouter",
            "model": "thinkingmachines/inkling",
            "protocol": "chat",
            "latencyMs": 9333
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.044Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-16-04-df5a7c43-66ff-460e-b535-353ed9811900",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-16-04-df5a7c43-66ff-460e-b535-353ed9811900",
        "createdAt": "2026-08-24T00:16:04.114Z",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "promptId": "luna-moth-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "opencode-go",
        "model": "gpt-5.6-luna",
        "medium": "watercolor",
        "paper": "night",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1703,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "2c211278a175c473",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "gpt-5.6-luna",
          "protocol": "responses",
          "latencyMs": 20518,
          "usage": {
            "input_tokens": 1171,
            "output_tokens": 2958,
            "total_tokens": 4129,
            "input_tokens_details": {
              "cached_tokens": 0,
              "cache_write_tokens": 1168
            },
            "output_tokens_details": {
              "reasoning_tokens": 432
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-16-04-df5a7c43-66ff-460e-b535-353ed9811900/painting.png",
        "projectSource": "sketches/2026-08-24T00-16-04-df5a7c43-66ff-460e-b535-353ed9811900/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-16-04-df5a7c43-66ff-460e-b535-353ed9811900.png",
        "source": "/images/model-painting-study/2026-08-24T00-16-04-df5a7c43-66ff-460e-b535-353ed9811900.js.txt",
        "stats": {
          "unique": 427,
          "meanLuma": 24.837214670138955,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "be49edc670a84cb371b6974881af151aa057b5956c2b459d42e21ce33045b536",
          "png": "ccee404e359aaee61f0e587b2024ffd4a35422551c861154884d3d1a23643c87",
          "raw": "be49edc670a84cb371b6974881af151aa057b5956c2b459d42e21ce33045b536"
        },
        "latencyMs": 20518,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1171,
              "output_tokens": 2958,
              "total_tokens": 4129,
              "input_tokens_details": {
                "cached_tokens": 0,
                "cache_write_tokens": 1168
              },
              "output_tokens_details": {
                "reasoning_tokens": 432
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "gpt-5.6-luna",
            "protocol": "responses",
            "latencyMs": 20518
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.044Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-16-19-c477f4c0-abd6-4421-8649-426f622d4c6e",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-16-19-c477f4c0-abd6-4421-8649-426f622d4c6e",
        "createdAt": "2026-08-24T00:16:19.573Z",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "promptId": "luna-moth-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "openrouter",
        "model": "thinkingmachines/inkling",
        "medium": "watercolor",
        "paper": "night",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1703,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "40a642d65e254a03",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "openrouter",
          "model": "thinkingmachines/inkling",
          "protocol": "chat",
          "latencyMs": 27917,
          "usage": {
            "prompt_tokens": 1182,
            "completion_tokens": 4695,
            "total_tokens": 5877,
            "cost": 0.02013765,
            "is_byok": false,
            "prompt_tokens_details": {
              "cached_tokens": 0,
              "cache_write_tokens": 0,
              "audio_tokens": 0,
              "video_tokens": 0
            },
            "cost_details": {
              "upstream_inference_cost": 0.02013765,
              "upstream_inference_prompt_cost": 0.0011229,
              "upstream_inference_completions_cost": 0.01901475
            },
            "completion_tokens_details": {
              "reasoning_tokens": 2425,
              "image_tokens": 0,
              "audio_tokens": 0
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-16-19-c477f4c0-abd6-4421-8649-426f622d4c6e/painting.png",
        "projectSource": "sketches/2026-08-24T00-16-19-c477f4c0-abd6-4421-8649-426f622d4c6e/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-16-19-c477f4c0-abd6-4421-8649-426f622d4c6e.png",
        "source": "/images/model-painting-study/2026-08-24T00-16-19-c477f4c0-abd6-4421-8649-426f622d4c6e.js.txt",
        "stats": {
          "unique": 382,
          "meanLuma": 21.339437847222253,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "09b89b4697ac4aabb59ea7af410828e0940719f6801c31d3796046a9b0f1f699",
          "png": "30d997761a097f51f325e397542ded84e10f790c0bec409eeae3be3d66c20fc0",
          "raw": "09b89b4697ac4aabb59ea7af410828e0940719f6801c31d3796046a9b0f1f699"
        },
        "latencyMs": 27917,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "prompt_tokens": 1182,
              "completion_tokens": 4695,
              "total_tokens": 5877,
              "cost": 0.02013765,
              "is_byok": false,
              "prompt_tokens_details": {
                "cached_tokens": 0,
                "cache_write_tokens": 0,
                "audio_tokens": 0,
                "video_tokens": 0
              },
              "cost_details": {
                "upstream_inference_cost": 0.02013765,
                "upstream_inference_prompt_cost": 0.0011229,
                "upstream_inference_completions_cost": 0.01901475
              },
              "completion_tokens_details": {
                "reasoning_tokens": 2425,
                "image_tokens": 0,
                "audio_tokens": 0
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "openrouter",
            "model": "thinkingmachines/inkling",
            "protocol": "chat",
            "latencyMs": 27917
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.045Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-16-41-471576e8-b214-46dc-88cb-123672fd9d7a",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-16-41-471576e8-b214-46dc-88cb-123672fd9d7a",
        "createdAt": "2026-08-24T00:16:41.723Z",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "promptId": "luna-moth-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "opencode-go",
        "model": "grok-4.5",
        "medium": "watercolor",
        "paper": "night",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1703,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "d5bd757db3ece6a4",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "grok-4.5",
          "protocol": "responses",
          "latencyMs": 55617,
          "usage": {
            "input_tokens": 1505,
            "output_tokens": 4503,
            "total_tokens": 6008,
            "input_tokens_details": {
              "cached_tokens": 128
            },
            "output_tokens_details": {
              "reasoning_tokens": 285
            }
          }
        },
        {
          "stage": "repair",
          "provider": "opencode-go",
          "model": "grok-4.5",
          "protocol": "responses",
          "latencyMs": 48013,
          "usage": {
            "input_tokens": 6102,
            "output_tokens": 4317,
            "total_tokens": 10419,
            "input_tokens_details": {
              "cached_tokens": 128
            },
            "output_tokens_details": {
              "reasoning_tokens": 110
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-16-41-471576e8-b214-46dc-88cb-123672fd9d7a/painting.png",
        "projectSource": "sketches/2026-08-24T00-16-41-471576e8-b214-46dc-88cb-123672fd9d7a/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-16-41-471576e8-b214-46dc-88cb-123672fd9d7a.png",
        "source": "/images/model-painting-study/2026-08-24T00-16-41-471576e8-b214-46dc-88cb-123672fd9d7a.js.txt",
        "stats": {
          "unique": 466,
          "meanLuma": 23.244989843749753,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "a3d5e31cc85e37a79ed51822d4f99d9a8795e8c82fd90884e9a6b9af60bc47d4",
          "png": "9f05224615fd1b8868f9752f11538e00f6598a92e0de9e18af63f042b6e80de0",
          "raw": "a5511b8daa0ef9eea90e878ddbfe4c7807c99e3d1a036ccf76b6917cb355bd6b"
        },
        "latencyMs": 103630,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1505,
              "output_tokens": 4503,
              "total_tokens": 6008,
              "input_tokens_details": {
                "cached_tokens": 128
              },
              "output_tokens_details": {
                "reasoning_tokens": 285
              }
            }
          },
          {
            "stage": "repair",
            "usage": {
              "input_tokens": 6102,
              "output_tokens": 4317,
              "total_tokens": 10419,
              "input_tokens_details": {
                "cached_tokens": 128
              },
              "output_tokens_details": {
                "reasoning_tokens": 110
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "grok-4.5",
            "protocol": "responses",
            "latencyMs": 55617
          },
          {
            "stage": "repair",
            "provider": "opencode-go",
            "model": "grok-4.5",
            "protocol": "responses",
            "latencyMs": 48013
          }
        ]
      },
      "failure": null,
      "eventCount": 5,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.045Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-18-23-68a712ee-f85d-4af7-89ab-b3e352190762",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-18-23-68a712ee-f85d-4af7-89ab-b3e352190762",
        "createdAt": "2026-08-24T00:18:23.755Z",
        "prompt": "a peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper",
        "promptId": "hibiscus-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "opencode-go",
        "model": "qwen3.8-max",
        "medium": "watercolor",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1701,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "49500c3845a6c972",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "qwen3.8-max",
          "protocol": "messages",
          "latencyMs": 24048,
          "usage": {
            "input_tokens": 1286,
            "output_tokens": 1719,
            "cache_creation_input_tokens": 0,
            "cache_read_input_tokens": 0
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-18-23-68a712ee-f85d-4af7-89ab-b3e352190762/painting.png",
        "projectSource": "sketches/2026-08-24T00-18-23-68a712ee-f85d-4af7-89ab-b3e352190762/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-18-23-68a712ee-f85d-4af7-89ab-b3e352190762.png",
        "source": "/images/model-painting-study/2026-08-24T00-18-23-68a712ee-f85d-4af7-89ab-b3e352190762.js.txt",
        "stats": {
          "unique": 125,
          "meanLuma": 229.8456338541705,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "6e0b0b5e29e2ea019550e116c7217a5b097ccbd1bf263b4019e934916fe4855b",
          "png": "d9ceb2e68c50624e88ee421d943d19959b7ca9fc302c57a7967a732323fb6d50",
          "raw": "6e0b0b5e29e2ea019550e116c7217a5b097ccbd1bf263b4019e934916fe4855b"
        },
        "latencyMs": 24048,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1286,
              "output_tokens": 1719,
              "cache_creation_input_tokens": 0,
              "cache_read_input_tokens": 0
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "qwen3.8-max",
            "protocol": "messages",
            "latencyMs": 24048
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.045Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-19-01-78b33177-43b8-4095-9d2a-7917716ced61",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-19-01-78b33177-43b8-4095-9d2a-7917716ced61",
        "createdAt": "2026-08-24T00:19:01.715Z",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "promptId": "luna-moth-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "provider": "opencode-go",
        "model": "qwen3.8-max",
        "medium": "watercolor",
        "paper": "night",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1703,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "1976a3111b09796b",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "qwen3.8-max",
          "protocol": "messages",
          "latencyMs": 26051,
          "usage": {
            "input_tokens": 1283,
            "output_tokens": 2319,
            "cache_creation_input_tokens": 0,
            "cache_read_input_tokens": 0
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-19-01-78b33177-43b8-4095-9d2a-7917716ced61/painting.png",
        "projectSource": "sketches/2026-08-24T00-19-01-78b33177-43b8-4095-9d2a-7917716ced61/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-19-01-78b33177-43b8-4095-9d2a-7917716ced61.png",
        "source": "/images/model-painting-study/2026-08-24T00-19-01-78b33177-43b8-4095-9d2a-7917716ced61.js.txt",
        "stats": {
          "unique": 312,
          "meanLuma": 20.598110763888332,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "5dd4f0f375550c6cb676c5321170adb5650ba3027185a40636467982e3f83981",
          "png": "bd8efb4fd63e0f37be4cfe180872c1ec47ad84c409435c3a198ea98997e9bef4",
          "raw": "5dd4f0f375550c6cb676c5321170adb5650ba3027185a40636467982e3f83981"
        },
        "latencyMs": 26051,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1283,
              "output_tokens": 2319,
              "cache_creation_input_tokens": 0,
              "cache_read_input_tokens": 0
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "qwen3.8-max",
            "protocol": "messages",
            "latencyMs": 26051
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.046Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-22-03-6b173950-6839-49ba-907e-b7270bdb3853",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-22-03-6b173950-6839-49ba-907e-b7270bdb3853",
        "createdAt": "2026-08-24T00:22:03.801Z",
        "prompt": "a peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper",
        "promptId": "hibiscus-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "directed-v3",
        "directionId": "hibiscus-directed-v3",
        "artDirection": "Paint one naturalistic hibiscus bloom spanning approximately x=110..475 and y=85..425. Use five overlapping, unequal 7–12-vertex petal contours around a throat near (300, 270); do not use circles for petals. Add one half-open bud near (455, 175), a curved stem descending toward (250, 560), two leaves, and two or three fallen petals in the lower-left third. Put the darkest peach-red and green marks at the throat, stamen, and stem junction. Keep tea stains extremely faint.",
        "provider": "openrouter",
        "model": "thinkingmachines/inkling",
        "medium": "watercolor",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1701,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "857b0cd453480173",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "openrouter",
          "model": "thinkingmachines/inkling",
          "protocol": "chat",
          "latencyMs": 13295,
          "usage": {
            "prompt_tokens": 1312,
            "completion_tokens": 2484,
            "total_tokens": 3796,
            "cost": 0.010801,
            "is_byok": false,
            "prompt_tokens_details": {
              "cached_tokens": 640,
              "cache_write_tokens": 0,
              "audio_tokens": 0,
              "video_tokens": 0
            },
            "cost_details": {
              "upstream_inference_cost": 0.010801,
              "upstream_inference_prompt_cost": 0.0007408,
              "upstream_inference_completions_cost": 0.0100602
            },
            "completion_tokens_details": {
              "reasoning_tokens": 295,
              "image_tokens": 0,
              "audio_tokens": 0
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-22-03-6b173950-6839-49ba-907e-b7270bdb3853/painting.png",
        "projectSource": "sketches/2026-08-24T00-22-03-6b173950-6839-49ba-907e-b7270bdb3853/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-22-03-6b173950-6839-49ba-907e-b7270bdb3853.png",
        "source": "/images/model-painting-study/2026-08-24T00-22-03-6b173950-6839-49ba-907e-b7270bdb3853.js.txt",
        "stats": {
          "unique": 203,
          "meanLuma": 229.45506935764232,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "43bbd085cd0a739b2096b962b973e12b96b3da9f1ab6c8fdde81c27f5a7b8dfa",
          "png": "2801dd5a4ce11b8d0170b5cd1270f379ff9fd9e38d0504f3b84c33ae9fe0a0bc",
          "raw": "43bbd085cd0a739b2096b962b973e12b96b3da9f1ab6c8fdde81c27f5a7b8dfa"
        },
        "latencyMs": 13295,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "prompt_tokens": 1312,
              "completion_tokens": 2484,
              "total_tokens": 3796,
              "cost": 0.010801,
              "is_byok": false,
              "prompt_tokens_details": {
                "cached_tokens": 640,
                "cache_write_tokens": 0,
                "audio_tokens": 0,
                "video_tokens": 0
              },
              "cost_details": {
                "upstream_inference_cost": 0.010801,
                "upstream_inference_prompt_cost": 0.0007408,
                "upstream_inference_completions_cost": 0.0100602
              },
              "completion_tokens_details": {
                "reasoning_tokens": 295,
                "image_tokens": 0,
                "audio_tokens": 0
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "openrouter",
            "model": "thinkingmachines/inkling",
            "protocol": "chat",
            "latencyMs": 13295
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:23:16.046Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-22-11-74a04cfa-3a90-4373-b674-fcfa57973ddc",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-22-11-74a04cfa-3a90-4373-b674-fcfa57973ddc",
        "createdAt": "2026-08-24T00:22:11.622Z",
        "prompt": "a peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper",
        "promptId": "hibiscus-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "directed-v3",
        "directionId": "hibiscus-directed-v3",
        "artDirection": "Paint one naturalistic hibiscus bloom spanning approximately x=110..475 and y=85..425. Use five overlapping, unequal 7–12-vertex petal contours around a throat near (300, 270); do not use circles for petals. Add one half-open bud near (455, 175), a curved stem descending toward (250, 560), two leaves, and two or three fallen petals in the lower-left third. Put the darkest peach-red and green marks at the throat, stamen, and stem junction. Keep tea stains extremely faint.",
        "provider": "opencode-go",
        "model": "grok-4.5",
        "medium": "watercolor",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1701,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "5ffec65a2f37d9e5",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "grok-4.5",
          "protocol": "responses",
          "latencyMs": 54628,
          "usage": {
            "input_tokens": 1636,
            "output_tokens": 4235,
            "total_tokens": 5871,
            "input_tokens_details": {
              "cached_tokens": 1408
            },
            "output_tokens_details": {
              "reasoning_tokens": 51
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-22-11-74a04cfa-3a90-4373-b674-fcfa57973ddc/painting.png",
        "projectSource": "sketches/2026-08-24T00-22-11-74a04cfa-3a90-4373-b674-fcfa57973ddc/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-22-11-74a04cfa-3a90-4373-b674-fcfa57973ddc.png",
        "source": "/images/model-painting-study/2026-08-24T00-22-11-74a04cfa-3a90-4373-b674-fcfa57973ddc.js.txt",
        "stats": {
          "unique": 197,
          "meanLuma": 230.0567970486145,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "307d0453d654dc17dded9ce0722d1a51e48f5d914de7c8af4a62bf7c06d26f66",
          "png": "c6274903fd17486cdfa70df71a909b4c2b60943963e65f59763785972d086e11",
          "raw": "307d0453d654dc17dded9ce0722d1a51e48f5d914de7c8af4a62bf7c06d26f66"
        },
        "latencyMs": 54628,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1636,
              "output_tokens": 4235,
              "total_tokens": 5871,
              "input_tokens_details": {
                "cached_tokens": 1408
              },
              "output_tokens_details": {
                "reasoning_tokens": 51
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "grok-4.5",
            "protocol": "responses",
            "latencyMs": 54628
          }
        ]
      },
      "failure": null,
      "eventCount": 3,
      "lastEvent": {
        "at": "2026-08-24T00:30:00.777Z",
        "type": "metadata-correction"
      }
    },
    {
      "attemptId": "2026-08-24T00-22-33-3a0573d7-b695-4cbd-8af4-580e9e57e653",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-22-33-3a0573d7-b695-4cbd-8af4-580e9e57e653",
        "createdAt": "2026-08-24T00:22:33.471Z",
        "prompt": "a crow on a telephone wire in winter fog, distant hills",
        "promptId": "crow-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "directed-v3",
        "directionId": "crow-directed-v3",
        "artDirection": "Paint one large, readable side-view crow spanning approximately x=150..440 and y=135..350, facing left. Build distinct closed contours for head, beak, chest, folded wing, belly, and tail; do not use circles for the body. Run the telephone wire across y=355 and place quiet fog-softened hills only in the lower third. The crow must be the darkest and crispest mass in the image; keep the full beak and tail on-canvas.",
        "provider": "openrouter",
        "model": "thinkingmachines/inkling",
        "medium": "ink",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1702,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "54f6c891093fbae8",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "openrouter",
          "model": "thinkingmachines/inkling",
          "protocol": "chat",
          "latencyMs": 42864,
          "usage": {
            "prompt_tokens": 1277,
            "completion_tokens": 6194,
            "total_tokens": 7471,
            "cost": 0.02538877,
            "is_byok": false,
            "prompt_tokens_details": {
              "cached_tokens": 1152,
              "cache_write_tokens": 0,
              "audio_tokens": 0,
              "video_tokens": 0
            },
            "cost_details": {
              "upstream_inference_cost": 0.02538877,
              "upstream_inference_prompt_cost": 0.00030307,
              "upstream_inference_completions_cost": 0.0250857
            },
            "completion_tokens_details": {
              "reasoning_tokens": 3921,
              "image_tokens": 0,
              "audio_tokens": 0
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-22-33-3a0573d7-b695-4cbd-8af4-580e9e57e653/painting.png",
        "projectSource": "sketches/2026-08-24T00-22-33-3a0573d7-b695-4cbd-8af4-580e9e57e653/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-22-33-3a0573d7-b695-4cbd-8af4-580e9e57e653.png",
        "source": "/images/model-painting-study/2026-08-24T00-22-33-3a0573d7-b695-4cbd-8af4-580e9e57e653.js.txt",
        "stats": {
          "unique": 256,
          "meanLuma": 222.93744270833574,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "bbed3f30b0a44ff21f88c35b3bd944a7cb6e5052cc330d089ab80f053cd221d7",
          "png": "31435f001fbc70153518ee4819c7bd82295a25253323f60c85bb3725e66030f2",
          "raw": "bbed3f30b0a44ff21f88c35b3bd944a7cb6e5052cc330d089ab80f053cd221d7"
        },
        "latencyMs": 42864,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "prompt_tokens": 1277,
              "completion_tokens": 6194,
              "total_tokens": 7471,
              "cost": 0.02538877,
              "is_byok": false,
              "prompt_tokens_details": {
                "cached_tokens": 1152,
                "cache_write_tokens": 0,
                "audio_tokens": 0,
                "video_tokens": 0
              },
              "cost_details": {
                "upstream_inference_cost": 0.02538877,
                "upstream_inference_prompt_cost": 0.00030307,
                "upstream_inference_completions_cost": 0.0250857
              },
              "completion_tokens_details": {
                "reasoning_tokens": 3921,
                "image_tokens": 0,
                "audio_tokens": 0
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "openrouter",
            "model": "thinkingmachines/inkling",
            "protocol": "chat",
            "latencyMs": 42864
          }
        ]
      },
      "failure": null,
      "eventCount": 2,
      "lastEvent": {
        "at": "2026-08-24T00:23:27.027Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 256,
          "meanLuma": 222.93744270833574,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-23-30-aa1fd085-ed16-4dc0-adcd-7fd3d000ba72",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-23-30-aa1fd085-ed16-4dc0-adcd-7fd3d000ba72",
        "createdAt": "2026-08-24T00:23:30.826Z",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "promptId": "luna-moth-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "directed-v3",
        "directionId": "luna-moth-directed-v3",
        "artDirection": "Paint one luna moth with wings spanning approximately x=90..510 and y=100..445 and a narrow body near x=285..315. Use separate closed contours for two forewings and two hindwings, with hindwing tails extending toward y=470; symmetry may be loose but anatomy must read. Place a soft lamplight halo in the upper-right and a dark windowsill across y=510, with only a few quiet garden marks beyond. Keep wing veins sparse and organic. Do not add arbitrary polygons, framing boxes, or circular diagrams.",
        "provider": "openrouter",
        "model": "thinkingmachines/inkling",
        "medium": "watercolor",
        "paper": "night",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1703,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "909e8d589723119b",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "openrouter",
          "model": "thinkingmachines/inkling",
          "protocol": "chat",
          "latencyMs": 17857,
          "usage": {
            "prompt_tokens": 1304,
            "completion_tokens": 2330,
            "total_tokens": 3634,
            "cost": 0.0107405,
            "is_byok": false,
            "prompt_tokens_details": {
              "cached_tokens": 0,
              "cache_write_tokens": 0,
              "audio_tokens": 0,
              "video_tokens": 0
            },
            "cost_details": {
              "upstream_inference_cost": 0.0107405,
              "upstream_inference_prompt_cost": 0.001304,
              "upstream_inference_completions_cost": 0.0094365
            },
            "completion_tokens_details": {
              "reasoning_tokens": 976,
              "image_tokens": 0,
              "audio_tokens": 0
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-23-30-aa1fd085-ed16-4dc0-adcd-7fd3d000ba72/painting.png",
        "projectSource": "sketches/2026-08-24T00-23-30-aa1fd085-ed16-4dc0-adcd-7fd3d000ba72/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-23-30-aa1fd085-ed16-4dc0-adcd-7fd3d000ba72.png",
        "source": "/images/model-painting-study/2026-08-24T00-23-30-aa1fd085-ed16-4dc0-adcd-7fd3d000ba72.js.txt",
        "stats": {
          "unique": 383,
          "meanLuma": 24.429903124999427,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "2a48fb483b2294c710c9f087f9be86c3fd43d8372652541ba211bb1c4dda3895",
          "png": "252c45f3b16bfb886d1527324b45f3b60b30b86beca23cc98a44494a9b4cc11d",
          "raw": "2a48fb483b2294c710c9f087f9be86c3fd43d8372652541ba211bb1c4dda3895"
        },
        "latencyMs": 17857,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "prompt_tokens": 1304,
              "completion_tokens": 2330,
              "total_tokens": 3634,
              "cost": 0.0107405,
              "is_byok": false,
              "prompt_tokens_details": {
                "cached_tokens": 0,
                "cache_write_tokens": 0,
                "audio_tokens": 0,
                "video_tokens": 0
              },
              "cost_details": {
                "upstream_inference_cost": 0.0107405,
                "upstream_inference_prompt_cost": 0.001304,
                "upstream_inference_completions_cost": 0.0094365
              },
              "completion_tokens_details": {
                "reasoning_tokens": 976,
                "image_tokens": 0,
                "audio_tokens": 0
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "openrouter",
            "model": "thinkingmachines/inkling",
            "protocol": "chat",
            "latencyMs": 17857
          }
        ]
      },
      "failure": null,
      "eventCount": 2,
      "lastEvent": {
        "at": "2026-08-24T00:24:01.926Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 383,
          "meanLuma": 24.429903124999427,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-23-33-756b040e-12bc-42f0-9b13-133857f8c2e7",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-23-33-756b040e-12bc-42f0-9b13-133857f8c2e7",
        "createdAt": "2026-08-24T00:23:33.421Z",
        "prompt": "a crow on a telephone wire in winter fog, distant hills",
        "promptId": "crow-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "directed-v3",
        "directionId": "crow-directed-v3",
        "artDirection": "Paint one large, readable side-view crow spanning approximately x=150..440 and y=135..350, facing left. Build distinct closed contours for head, beak, chest, folded wing, belly, and tail; do not use circles for the body. Run the telephone wire across y=355 and place quiet fog-softened hills only in the lower third. The crow must be the darkest and crispest mass in the image; keep the full beak and tail on-canvas.",
        "provider": "opencode-go",
        "model": "grok-4.5",
        "medium": "ink",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1702,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "6f96491d8b4be496",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "grok-4.5",
          "protocol": "responses",
          "latencyMs": 42602,
          "usage": {
            "input_tokens": 1599,
            "output_tokens": 2763,
            "total_tokens": 4362,
            "input_tokens_details": {
              "cached_tokens": 128
            },
            "output_tokens_details": {
              "reasoning_tokens": 36
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-23-33-756b040e-12bc-42f0-9b13-133857f8c2e7/painting.png",
        "projectSource": "sketches/2026-08-24T00-23-33-756b040e-12bc-42f0-9b13-133857f8c2e7/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-23-33-756b040e-12bc-42f0-9b13-133857f8c2e7.png",
        "source": "/images/model-painting-study/2026-08-24T00-23-33-756b040e-12bc-42f0-9b13-133857f8c2e7.js.txt",
        "stats": {
          "unique": 400,
          "meanLuma": 222.28823810764098,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "6dc7da5353d5fd5639d113889d1993501ab21d9ae849e92e59eae2d89d4e5517",
          "png": "71695adcfe79628a79917d663bbb0b838f82cbfdd6a58558958faca329a61cd3",
          "raw": "6dc7da5353d5fd5639d113889d1993501ab21d9ae849e92e59eae2d89d4e5517"
        },
        "latencyMs": 42602,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1599,
              "output_tokens": 2763,
              "total_tokens": 4362,
              "input_tokens_details": {
                "cached_tokens": 128
              },
              "output_tokens_details": {
                "reasoning_tokens": 36
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "grok-4.5",
            "protocol": "responses",
            "latencyMs": 42602
          }
        ]
      },
      "failure": null,
      "eventCount": 2,
      "lastEvent": {
        "at": "2026-08-24T00:24:30.705Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 400,
          "meanLuma": 222.28823810764098,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-23-36-405e2723-f9c5-4f8a-af67-e4632d24d17c",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-23-36-405e2723-f9c5-4f8a-af67-e4632d24d17c",
        "createdAt": "2026-08-24T00:23:36.355Z",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "promptId": "luna-moth-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": null,
        "directionId": null,
        "artDirection": null,
        "provider": "local-render",
        "sourceProvider": null,
        "model": "deepseek-v4-flash",
        "medium": "watercolor",
        "paper": "night",
        "size": 600,
        "deviceScaleFactor": 2,
        "parentAttemptId": "2026-08-23T22-58-12-a-luna-moth-on-a-dark-windowsill-lamplig"
      },
      "promptRequestId": null,
      "apiResponses": [],
      "result": {
        "projectImage": "sketches/2026-08-24T00-23-36-405e2723-f9c5-4f8a-af67-e4632d24d17c/painting.png",
        "projectSource": "sketches/2026-08-24T00-23-36-405e2723-f9c5-4f8a-af67-e4632d24d17c/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-23-36-405e2723-f9c5-4f8a-af67-e4632d24d17c.png",
        "source": "/images/model-painting-study/2026-08-24T00-23-36-405e2723-f9c5-4f8a-af67-e4632d24d17c.js.txt",
        "stats": {
          "unique": 377,
          "meanLuma": 20.71993637152791,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "226bcbb5bb27028c7d4da4b71e2e5e502df165c80175d95507f78706c3166a11",
          "png": "1b8f70f4db471cb277bb62df1233f604d86bb8125e1d2a8ef81319abb240dd1f",
          "raw": null
        },
        "latencyMs": null,
        "usage": null,
        "apiCalls": []
      },
      "failure": null,
      "eventCount": 1,
      "lastEvent": {
        "at": "2026-08-24T00:24:14.033Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 377,
          "meanLuma": 20.71993637152791,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-24-43-0348811a-32a7-4b6e-9995-5b05cacb706f",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-24-43-0348811a-32a7-4b6e-9995-5b05cacb706f",
        "createdAt": "2026-08-24T00:24:43.743Z",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "promptId": "luna-moth-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "directed-v3",
        "directionId": "luna-moth-directed-v3",
        "artDirection": "Paint one luna moth with wings spanning approximately x=90..510 and y=100..445 and a narrow body near x=285..315. Use separate closed contours for two forewings and two hindwings, with hindwing tails extending toward y=470; symmetry may be loose but anatomy must read. Place a soft lamplight halo in the upper-right and a dark windowsill across y=510, with only a few quiet garden marks beyond. Keep wing veins sparse and organic. Do not add arbitrary polygons, framing boxes, or circular diagrams.",
        "provider": "opencode-go",
        "model": "grok-4.5",
        "medium": "watercolor",
        "paper": "night",
        "size": 600,
        "deviceScaleFactor": 1,
        "seed": 1703,
        "index": 1,
        "total": 1
      },
      "promptRequestId": "b56cf4588d60b93d",
      "apiResponses": [
        {
          "stage": "generate",
          "provider": "opencode-go",
          "model": "grok-4.5",
          "protocol": "responses",
          "latencyMs": 60071,
          "usage": {
            "input_tokens": 1626,
            "output_tokens": 4311,
            "total_tokens": 5937,
            "input_tokens_details": {
              "cached_tokens": 128
            },
            "output_tokens_details": {
              "reasoning_tokens": 59
            }
          }
        }
      ],
      "result": {
        "projectImage": "sketches/2026-08-24T00-24-43-0348811a-32a7-4b6e-9995-5b05cacb706f/painting.png",
        "projectSource": "sketches/2026-08-24T00-24-43-0348811a-32a7-4b6e-9995-5b05cacb706f/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-24-43-0348811a-32a7-4b6e-9995-5b05cacb706f.png",
        "source": "/images/model-painting-study/2026-08-24T00-24-43-0348811a-32a7-4b6e-9995-5b05cacb706f.js.txt",
        "stats": {
          "unique": 395,
          "meanLuma": 23.720111805554556,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "1f60e59e7b252e3c34bee1db7da8ab4d1ced2ce743a5cd50e864ce35bd068155",
          "png": "37f1a5aca16bb5159833ff39f5000f7a0167db29314d696a6527493567da41e2",
          "raw": "1f60e59e7b252e3c34bee1db7da8ab4d1ced2ce743a5cd50e864ce35bd068155"
        },
        "latencyMs": 60071,
        "usage": [
          {
            "stage": "generate",
            "usage": {
              "input_tokens": 1626,
              "output_tokens": 4311,
              "total_tokens": 5937,
              "input_tokens_details": {
                "cached_tokens": 128
              },
              "output_tokens_details": {
                "reasoning_tokens": 59
              }
            }
          }
        ],
        "apiCalls": [
          {
            "stage": "generate",
            "provider": "opencode-go",
            "model": "grok-4.5",
            "protocol": "responses",
            "latencyMs": 60071
          }
        ]
      },
      "failure": null,
      "eventCount": 2,
      "lastEvent": {
        "at": "2026-08-24T00:26:06.005Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 395,
          "meanLuma": 23.720111805554556,
          "w": 600,
          "h": 600,
          "deviceScaleFactor": 1,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-27-12-403acaab-a3c5-43bf-9479-46da6043e6a0",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-27-12-403acaab-a3c5-43bf-9479-46da6043e6a0",
        "createdAt": "2026-08-24T00:27:12.914Z",
        "prompt": "a peach hibiscus, half-open bud, fallen petals, tea-stained field journal paper",
        "promptId": "hibiscus-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "directed-v3",
        "directionId": "hibiscus-directed-v3",
        "artDirection": "Paint one naturalistic hibiscus bloom spanning approximately x=110..475 and y=85..425. Use five overlapping, unequal 7–12-vertex petal contours around a throat near (300, 270); do not use circles for petals. Add one half-open bud near (455, 175), a curved stem descending toward (250, 560), two leaves, and two or three fallen petals in the lower-left third. Put the darkest peach-red and green marks at the throat, stamen, and stem junction. Keep tea stains extremely faint.",
        "provider": "local-render",
        "sourceProvider": "openrouter",
        "model": "thinkingmachines/inkling",
        "medium": "watercolor",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 2,
        "parentAttemptId": "2026-08-24T00-22-03-6b173950-6839-49ba-907e-b7270bdb3853"
      },
      "promptRequestId": null,
      "apiResponses": [],
      "result": {
        "projectImage": "sketches/2026-08-24T00-27-12-403acaab-a3c5-43bf-9479-46da6043e6a0/painting.png",
        "projectSource": "sketches/2026-08-24T00-27-12-403acaab-a3c5-43bf-9479-46da6043e6a0/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-27-12-403acaab-a3c5-43bf-9479-46da6043e6a0.png",
        "source": "/images/model-painting-study/2026-08-24T00-27-12-403acaab-a3c5-43bf-9479-46da6043e6a0.js.txt",
        "stats": {
          "unique": 185,
          "meanLuma": 229.57230121528124,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "43bbd085cd0a739b2096b962b973e12b96b3da9f1ab6c8fdde81c27f5a7b8dfa",
          "png": "73007137c39e303765f3a97e0bec5b5abad800588a820eaae4608632c727f22c",
          "raw": null
        },
        "latencyMs": null,
        "usage": null,
        "apiCalls": []
      },
      "failure": null,
      "eventCount": 1,
      "lastEvent": {
        "at": "2026-08-24T00:27:24.915Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 185,
          "meanLuma": 229.57230121528124,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-27-18-4567d058-915e-4ccc-ab69-503a4511205d",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-27-18-4567d058-915e-4ccc-ab69-503a4511205d",
        "createdAt": "2026-08-24T00:27:18.206Z",
        "prompt": "a crow on a telephone wire in winter fog, distant hills",
        "promptId": "crow-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "directed-v3",
        "directionId": "crow-directed-v3",
        "artDirection": "Paint one large, readable side-view crow spanning approximately x=150..440 and y=135..350, facing left. Build distinct closed contours for head, beak, chest, folded wing, belly, and tail; do not use circles for the body. Run the telephone wire across y=355 and place quiet fog-softened hills only in the lower third. The crow must be the darkest and crispest mass in the image; keep the full beak and tail on-canvas.",
        "provider": "local-render",
        "sourceProvider": "opencode-go",
        "model": "grok-4.5",
        "medium": "ink",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 2,
        "parentAttemptId": "2026-08-24T00-23-33-756b040e-12bc-42f0-9b13-133857f8c2e7"
      },
      "promptRequestId": null,
      "apiResponses": [],
      "result": {
        "projectImage": "sketches/2026-08-24T00-27-18-4567d058-915e-4ccc-ab69-503a4511205d/painting.png",
        "projectSource": "sketches/2026-08-24T00-27-18-4567d058-915e-4ccc-ab69-503a4511205d/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-27-18-4567d058-915e-4ccc-ab69-503a4511205d.png",
        "source": "/images/model-painting-study/2026-08-24T00-27-18-4567d058-915e-4ccc-ab69-503a4511205d.js.txt",
        "stats": {
          "unique": 345,
          "meanLuma": 223.26619079861356,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "6dc7da5353d5fd5639d113889d1993501ab21d9ae849e92e59eae2d89d4e5517",
          "png": "c9e40899706283b601e61bf4f06912874609a944ea2aa93afb57489d1fcabed5",
          "raw": null
        },
        "latencyMs": null,
        "usage": null,
        "apiCalls": []
      },
      "failure": null,
      "eventCount": 1,
      "lastEvent": {
        "at": "2026-08-24T00:27:33.582Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 345,
          "meanLuma": 223.26619079861356,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-27-25-fd19c191-f0d8-459e-94d2-00a3e6b3779e",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-27-25-fd19c191-f0d8-459e-94d2-00a3e6b3779e",
        "createdAt": "2026-08-24T00:27:25.896Z",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "promptId": "luna-moth-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "taste-v2",
        "directionId": null,
        "artDirection": null,
        "provider": "local-render",
        "sourceProvider": "opencode-go",
        "model": "qwen3.8-max",
        "medium": "watercolor",
        "paper": "night",
        "size": 600,
        "deviceScaleFactor": 2,
        "parentAttemptId": "2026-08-24T00-19-01-78b33177-43b8-4095-9d2a-7917716ced61"
      },
      "promptRequestId": null,
      "apiResponses": [],
      "result": {
        "projectImage": "sketches/2026-08-24T00-27-25-fd19c191-f0d8-459e-94d2-00a3e6b3779e/painting.png",
        "projectSource": "sketches/2026-08-24T00-27-25-fd19c191-f0d8-459e-94d2-00a3e6b3779e/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-27-25-fd19c191-f0d8-459e-94d2-00a3e6b3779e.png",
        "source": "/images/model-painting-study/2026-08-24T00-27-25-fd19c191-f0d8-459e-94d2-00a3e6b3779e.js.txt",
        "stats": {
          "unique": 272,
          "meanLuma": 19.726989930555053,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "5dd4f0f375550c6cb676c5321170adb5650ba3027185a40636467982e3f83981",
          "png": "f43a7e9612e9e222ec7389e7f3f4f74e8420c3c4ae1fc32f9606151e638c3a00",
          "raw": null
        },
        "latencyMs": null,
        "usage": null,
        "apiCalls": []
      },
      "failure": null,
      "eventCount": 1,
      "lastEvent": {
        "at": "2026-08-24T00:27:49.065Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 272,
          "meanLuma": 19.726989930555053,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-27-37-ee9f23b2-4618-4753-babb-f0dc01c39021",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-27-37-ee9f23b2-4618-4753-babb-f0dc01c39021",
        "createdAt": "2026-08-24T00:27:37.079Z",
        "prompt": "a luna moth on a dark windowsill, lamplight, night garden beyond",
        "promptId": "luna-moth-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": "directed-v3",
        "directionId": "luna-moth-directed-v3",
        "artDirection": "Paint one luna moth with wings spanning approximately x=90..510 and y=100..445 and a narrow body near x=285..315. Use separate closed contours for two forewings and two hindwings, with hindwing tails extending toward y=470; symmetry may be loose but anatomy must read. Place a soft lamplight halo in the upper-right and a dark windowsill across y=510, with only a few quiet garden marks beyond. Keep wing veins sparse and organic. Do not add arbitrary polygons, framing boxes, or circular diagrams.",
        "provider": "local-render",
        "sourceProvider": "opencode-go",
        "model": "grok-4.5",
        "medium": "watercolor",
        "paper": "night",
        "size": 600,
        "deviceScaleFactor": 2,
        "parentAttemptId": "2026-08-24T00-24-43-0348811a-32a7-4b6e-9995-5b05cacb706f"
      },
      "promptRequestId": null,
      "apiResponses": [],
      "result": {
        "projectImage": "sketches/2026-08-24T00-27-37-ee9f23b2-4618-4753-babb-f0dc01c39021/painting.png",
        "projectSource": "sketches/2026-08-24T00-27-37-ee9f23b2-4618-4753-babb-f0dc01c39021/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-27-37-ee9f23b2-4618-4753-babb-f0dc01c39021.png",
        "source": "/images/model-painting-study/2026-08-24T00-27-37-ee9f23b2-4618-4753-babb-f0dc01c39021.js.txt",
        "stats": {
          "unique": 378,
          "meanLuma": 23.124534461804572,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "1f60e59e7b252e3c34bee1db7da8ab4d1ced2ce743a5cd50e864ce35bd068155",
          "png": "5899b0ac5859324fe6ff2efa431723763ac9bcfda16fe46ffcf6df025125ca51",
          "raw": null
        },
        "latencyMs": null,
        "usage": null,
        "apiCalls": []
      },
      "failure": null,
      "eventCount": 1,
      "lastEvent": {
        "at": "2026-08-24T00:27:58.509Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 378,
          "meanLuma": 23.124534461804572,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    },
    {
      "attemptId": "2026-08-24T00-28-23-17e31052-62af-473a-aa60-eee1764adfaf",
      "status": "success",
      "request": {
        "attemptId": "2026-08-24T00-28-23-17e31052-62af-473a-aa60-eee1764adfaf",
        "createdAt": "2026-08-24T00:28:23.186Z",
        "prompt": "a crow on a telephone wire in winter fog, distant hills",
        "promptId": "crow-core-v1",
        "experimentId": "2026-08-23-model-painting-study",
        "promptSpec": null,
        "directionId": null,
        "artDirection": null,
        "provider": "local-render",
        "sourceProvider": null,
        "model": "deepseek-v4-flash",
        "medium": "ink",
        "paper": "cream",
        "size": 600,
        "deviceScaleFactor": 2,
        "parentAttemptId": "2026-08-23T22-55-51-a-crow-on-a-telephone-wire-in-winter-fog"
      },
      "promptRequestId": null,
      "apiResponses": [],
      "result": {
        "projectImage": "sketches/2026-08-24T00-28-23-17e31052-62af-473a-aa60-eee1764adfaf/painting.png",
        "projectSource": "sketches/2026-08-24T00-28-23-17e31052-62af-473a-aa60-eee1764adfaf/sketch.js",
        "image": "/images/model-painting-study/2026-08-24T00-28-23-17e31052-62af-473a-aa60-eee1764adfaf.png",
        "source": "/images/model-painting-study/2026-08-24T00-28-23-17e31052-62af-473a-aa60-eee1764adfaf.js.txt",
        "stats": {
          "unique": 329,
          "meanLuma": 224.57774522569665,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        },
        "hashes": {
          "code": "c8cc14a881740cd364eb45b16ce31f4a421f09daa9560a871b4501c656cf1c4e",
          "png": "19031cece907811e3e219f183b1282e9ccbe69580830f13ba090627cfc04f894",
          "raw": null
        },
        "latencyMs": null,
        "usage": null,
        "apiCalls": []
      },
      "failure": null,
      "eventCount": 1,
      "lastEvent": {
        "at": "2026-08-24T00:28:28.601Z",
        "type": "render",
        "status": "success",
        "stats": {
          "unique": 329,
          "meanLuma": 224.57774522569665,
          "w": 1200,
          "h": 1200,
          "deviceScaleFactor": 2,
          "rendererBuild": "vendored-p5.brush+centroid-fallback-fix"
        }
      }
    }
  ]
}
