{
  "$schema": "https://pi-tui.ratstack.sh/schema/pattern.schema.json",
  "aka": [
    "Width-keyed cache"
  ],
  "animated": false,
  "apis": [
    {
      "name": "Component",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#understand-the-component-model"
    },
    {
      "name": "wrapTextWithAnsi",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#understand-the-component-model"
    },
    {
      "name": "theme.style",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#apply-themes-correctly"
    },
    {
      "name": "getThemeByName",
      "url": null
    }
  ],
  "applicability": [
    "Use this when immutable message content needs repeated wrapping or preview rendering."
  ],
  "category": "rendering",
  "categoryLabel": "Rendering and performance",
  "consequences": [
    "Cached layout can survive theme changes without retaining old colours.",
    "Content mutation or width changes require cache invalidation."
  ],
  "family": "presentation",
  "familyLabel": "Presentation",
  "id": "late-paint",
  "implementation": [
    "Invalidate layout when its content or width changes.",
    "Invalidation must not erase application state.",
    "Do not cache permanently coloured strings."
  ],
  "intent": "Cache plain layout by width and apply theme styling during rendering.",
  "jsonUrl": "https://pi-tui.ratstack.sh/patterns/late-paint.json",
  "kind": "component",
  "knownUses": [
    {
      "example": "inline-message-cache",
      "moreRefs": 0,
      "refs": [
        {
          "file": "ui/inline-message.ts",
          "lines": "10-125",
          "sha": "a5fad4df",
          "url": "https://github.com/nicobailon/pi-intercom/blob/a5fad4df2a9fe4909bf4d9b06263c8316976b57d/ui/inline-message.ts#L10-L125"
        }
      ],
      "repo": "pi-intercom",
      "repoUrl": "https://github.com/nicobailon/pi-intercom",
      "title": "Cache message layout separately from live theme styling"
    },
    {
      "example": "subagents-widget-projection",
      "moreRefs": 0,
      "refs": [
        {
          "file": "src/tui/render.ts",
          "lines": "2520-2585",
          "sha": "6826b054",
          "url": "https://github.com/nicobailon/pi-subagents/blob/6826b0545216077195ae8ffe468a6434715814b7/src/tui/render.ts#L2520-L2585"
        },
        {
          "file": "src/tui/render.ts",
          "lines": "3060-3110",
          "sha": "6826b054",
          "url": "https://github.com/nicobailon/pi-subagents/blob/6826b0545216077195ae8ffe468a6434715814b7/src/tui/render.ts#L3060-L3110"
        }
      ],
      "repo": "pi-subagents",
      "repoUrl": "https://github.com/nicobailon/pi-subagents",
      "title": "Project workflow state before rendering status widgets"
    }
  ],
  "linkedFrom": [
    {
      "how": "caches layout rather than fetched detail",
      "id": "lazy-peek",
      "jsonUrl": "https://pi-tui.ratstack.sh/patterns/lazy-peek.json",
      "mdUrl": "https://pi-tui.ratstack.sh/patterns/lazy-peek.md",
      "name": "Lazy Peek",
      "url": "https://pi-tui.ratstack.sh/patterns/lazy-peek/"
    },
    {
      "how": "reuses wrapped message layout",
      "id": "message-fold",
      "jsonUrl": "https://pi-tui.ratstack.sh/patterns/message-fold.json",
      "mdUrl": "https://pi-tui.ratstack.sh/patterns/message-fold.md",
      "name": "Message Fold",
      "url": "https://pi-tui.ratstack.sh/patterns/message-fold/"
    }
  ],
  "links": {
    "agentGuide": "https://pi-tui.ratstack.sh/llms.txt",
    "index": "https://pi-tui.ratstack.sh/patterns.md",
    "skill": "https://pi-tui.ratstack.sh/skills/build-pi-tui-component.md"
  },
  "mdUrl": "https://pi-tui.ratstack.sh/patterns/late-paint.md",
  "motivation": "Intercom's inline messages reuse immutable wrapped text across widths and apply colours while rendering.",
  "name": "Late Paint",
  "participants": [
    {
      "name": "Component",
      "role": "Renders width-bounded lines and invalidates cached output.",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#understand-the-component-model"
    },
    {
      "name": "wrapTextWithAnsi",
      "role": "Wraps text while preserving styling across lines.",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#understand-the-component-model"
    },
    {
      "name": "theme.style",
      "role": "Styles text through semantic or concrete colours.",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#apply-themes-correctly"
    },
    {
      "name": "Plain layout cache",
      "role": "Retains immutable wrapping without embedding theme colours.",
      "url": null
    }
  ],
  "pi": "1.0.3",
  "related": [
    {
      "how": "caches loaded data instead of layout",
      "id": "lazy-peek",
      "jsonUrl": "https://pi-tui.ratstack.sh/patterns/lazy-peek.json",
      "mdUrl": "https://pi-tui.ratstack.sh/patterns/lazy-peek.md",
      "name": "Lazy Peek",
      "url": "https://pi-tui.ratstack.sh/patterns/lazy-peek/"
    }
  ],
  "sampleCode": {
    "code": "// Late Paint: cache plain width-keyed layout; apply the active theme last.\nimport { wrapTextWithAnsi, type Component } from \"@earendil-works/pi-tui\";\nimport { Theme } from \"@earendil-works/pi-coding-agent\";\nimport type { PatternStory } from \"../../../src/pattern.ts\";\n\nexport const story: PatternStory = {\n  id: \"late-paint\", title: \"Late Paint\", kind: \"component\",\n  apis: [\"Component\", \"wrapTextWithAnsi\", \"theme.style\", \"getThemeByName\"], rows: 12,\n  states: [\n    { id: \"cached\", label: \"Cached layout\" },\n    { id: \"resized\", label: \"Width changed\", steps: [{ type: \"action\", name: \"resize-probe\" }] },\n    { id: \"theme-change\", label: \"Theme round trip\", steps: [{ type: \"action\", name: \"theme-probe\" }] },\n  ],\n  async setup({ theme, tui, action }) {\n    // This shipped helper is not a root export in Pi 1.0.3.\n    const module = await import(new URL(\"./modes/interactive/theme/theme.js\",\n      import.meta.resolve(\"@earendil-works/pi-coding-agent\")).href);\n    const opposite: unknown = module.getThemeByName(theme.appearance === \"dark\" ? \"light\" : \"dark\");\n    if (!(opposite instanceof Theme)) throw new Error(\"Pinned theme missing\");\n    const message = \"Review the parser changes before the next build. Keep the wrapped message when the terminal narrows; repaint it when the theme changes.\";\n    const layoutCache = new Map<number, string[]>();\n    let activeTheme = theme, note = \"Plain wrapping reused on repeat render\";\n    const view: Component = {\n      invalidate() { layoutCache.clear(); },\n      render(width) {\n        if (!layoutCache.has(width)) layoutCache.set(width, wrapTextWithAnsi(message, width));\n        return [\n          ...wrapTextWithAnsi(\"Parser review · immutable message\", width).map(line =>\n            activeTheme.style(line, { fg: \"accent\", bold: true })),\n          \"\",\n          ...layoutCache.get(width)!.map(line => activeTheme.style(line, { fg: \"text\" })),\n          \"\",\n          ...wrapTextWithAnsi(note, width).map(line => activeTheme.fg(\"muted\", line)),\n        ];\n      },\n    };\n    action(\"resize-probe\", () => {\n      view.invalidate();\n      view.render(Math.max(20, Math.floor(tui.terminal.columns / 2)));\n      note = \"Narrow layout rebuilt; message retained\";\n      tui.requestRender();\n    });\n    action(\"theme-probe\", () => {\n      // Check the opposite theme offscreen; capture the supplied matrix theme.\n      activeTheme = opposite;\n      view.render(tui.terminal.columns);\n      activeTheme = theme;\n      note = \"Theme round trip · same plain layout\";\n      tui.requestRender();\n    });\n    return view;\n  },\n};\n",
    "lang": "ts",
    "path": "stories/patterns/presentation/late-paint.ts"
  },
  "states": [
    {
      "dont": false,
      "expectFail": [],
      "frames": [
        {
          "alt": "Late Paint, Cached layout state, 40 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/cached-40-dark.1121f526f3d3.webp",
          "theme": "dark",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Late Paint, Cached layout state, 40 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/cached-40-light.aebb9aa3f897.webp",
          "theme": "light",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Late Paint, Cached layout state, 60 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/cached-60-dark.4d38ad8c15fa.webp",
          "theme": "dark",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Late Paint, Cached layout state, 60 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/cached-60-light.cdfb56bd28f2.webp",
          "theme": "light",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Late Paint, Cached layout state, 80 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/cached-80-dark.78f73c773210.webp",
          "theme": "dark",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Late Paint, Cached layout state, 80 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/cached-80-light.c69bf44eb85d.webp",
          "theme": "light",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Late Paint, Cached layout state, 120 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/cached-120-dark.14f607749372.webp",
          "theme": "dark",
          "w": 2400,
          "width": 120
        },
        {
          "alt": "Late Paint, Cached layout state, 120 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/cached-120-light.e0c54de6dae0.webp",
          "theme": "light",
          "w": 2400,
          "width": 120
        }
      ],
      "how": "Render an immutable synthetic message using a width-keyed wrapped layout.",
      "id": "cached",
      "label": "Cached layout",
      "problems": []
    },
    {
      "dont": false,
      "expectFail": [],
      "frames": [
        {
          "alt": "Late Paint, Width changed state, 40 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/resized-40-dark.b95859643210.webp",
          "theme": "dark",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Late Paint, Width changed state, 40 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/resized-40-light.11cb037cdb68.webp",
          "theme": "light",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Late Paint, Width changed state, 60 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/resized-60-dark.36b04076f4a9.webp",
          "theme": "dark",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Late Paint, Width changed state, 60 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/resized-60-light.eeb823c4dd32.webp",
          "theme": "light",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Late Paint, Width changed state, 80 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/resized-80-dark.f0230947cacc.webp",
          "theme": "dark",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Late Paint, Width changed state, 80 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/resized-80-light.f06412fc6855.webp",
          "theme": "light",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Late Paint, Width changed state, 120 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/resized-120-dark.e707bd23e4fe.webp",
          "theme": "dark",
          "w": 2400,
          "width": 120
        },
        {
          "alt": "Late Paint, Width changed state, 120 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/resized-120-light.c7ab8f42e652.webp",
          "theme": "light",
          "w": 2400,
          "width": 120
        }
      ],
      "how": "Change width and rebuild wrapping without clearing the message.",
      "id": "resized",
      "label": "Width changed",
      "problems": []
    },
    {
      "dont": false,
      "expectFail": [],
      "frames": [
        {
          "alt": "Late Paint, Theme changed state, 40 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/theme-change-40-dark.c16d190a3008.webp",
          "theme": "dark",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Late Paint, Theme changed state, 40 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/theme-change-40-light.785f696dfce1.webp",
          "theme": "light",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Late Paint, Theme changed state, 60 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/theme-change-60-dark.e71318b4bcef.webp",
          "theme": "dark",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Late Paint, Theme changed state, 60 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/theme-change-60-light.cac80a950c99.webp",
          "theme": "light",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Late Paint, Theme changed state, 80 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/theme-change-80-dark.11cad50ab57d.webp",
          "theme": "dark",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Late Paint, Theme changed state, 80 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/theme-change-80-light.ac63730bdca3.webp",
          "theme": "light",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Late Paint, Theme changed state, 120 columns, dark theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/theme-change-120-dark.fe8d503f4e8e.webp",
          "theme": "dark",
          "w": 2400,
          "width": 120
        },
        {
          "alt": "Late Paint, Theme changed state, 120 columns, light theme, 8 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 352,
          "rows": 8,
          "still": "https://pi-tui.ratstack.sh/frames/late-paint/theme-change-120-light.69c4a1b98dfc.webp",
          "theme": "light",
          "w": 2400,
          "width": 120
        }
      ],
      "how": "Reapply the active theme without retaining old ANSI colours.",
      "id": "theme-change",
      "label": "Theme changed",
      "problems": []
    }
  ],
  "structure": "immutable text + width -> cache\ncached layout + theme -> lines",
  "thumbnails": {
    "dark": {
      "animation": null,
      "src": "https://pi-tui.ratstack.sh/thumbs/late-paint/dark.705a24adaeb4.webp"
    },
    "light": {
      "animation": null,
      "src": "https://pi-tui.ratstack.sh/thumbs/late-paint/light.02b06196a33c.webp"
    }
  },
  "url": "https://pi-tui.ratstack.sh/patterns/late-paint/",
  "widths": [
    40,
    60,
    80,
    120
  ]
}
