---
title: "Fix & restyle the plan load skeleton"
brief: "The plan page flashed an ugly skeleton, then an 'start with an HTML plan' empty state, then back to the skeleton on a loop. Stop the flip-flop and replace the skeleton with a calm, textless loader that matches the real artboard layout."
version: 2
planId: "plan_d48253b962f344d1"
source: "agent-native-plan"
---

<RichText id="b1">

### Objective & done criteria

Loading a plan should show one calm, textless skeleton that matches the real artboard + document layout, then resolve straight into the plan. **Done** = no flip between skeleton and the 'start with an HTML plan' empty state, and the skeleton no longer looks like scattered gray boxes.

</RichText>

<RichText id="b2">

### Root cause

The page rendered an empty-state ('start with an HTML plan') whenever the bundle was momentarily empty, while a 3s refetch kept clearing the bundle — so it oscillated skeleton → empty-state → skeleton. The skeleton itself also used ad-hoc gray rectangles instead of the artboard register.

</RichText>

<ImplementationMap
  id="b3"
  files={[
    {
      path: "app/pages/PlansPage.tsx",
      note: "PlanSkeleton / PlanCanvasSkeleton — gate on planQuery.isLoading only; show skeleton until first settled bundle",
    },
    {
      path: "app/hooks/use-plans.ts",
      note: "stop clearing bundle on background refetch (keepPreviousData)",
    },
    {
      path: "app/components/plan/wireframe/html-artboard.css",
      note: "skeleton register: textless neutral bars (data.skeleton)",
    },
  ]}
/>

<Decision
  id="b4"
  question={"What loading treatment?"}
  options={[
    {
      id: "o1",
      label: "Spinner while loading",
      detail: "Cheap, but no sense of the page shape; feels slower.",
    },
    {
      id: "o2",
      label: "Layout-matched skeleton (canvas bars + doc bars)",
      detail: "Reads as the real plan settling in; no flash, no flip-flop.",
      recommended: true,
    },
  ]}
/>

<RichText id="b5">

### Validation

- Hard-reload a plan 10× → only the calm skeleton shows, never the empty-state text.
- Throttle network → skeleton holds, then resolves directly to content.
- Skeleton has no text and no sketch strokes (skeleton register).

</RichText>
