# Canvas Brand Web Design

> Use when the user asks JarvisHub AI Chat or a `webHero` workflow to generate a website, landing page, homepage, brand-style web design, preview-first webpage workflow, or wants section screenshots, webpage assets, and final HTML to be produced as one staged flow.

- Skill: `lyl1015/canvas-brand-web-design` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lyl1015/canvas-brand-web-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lyl1015/canvas-brand-web-design/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: lyl1015 (https://skillmd.com/u/lyl1015)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lyl1015/canvas-brand-web-design

---


# JarvisHub Brand Web Design

Turn a vague web request into a staged JarvisHub production flow that stays visually coherent from preview images to assets to final code.

## Success Definition

Treat a `webHero` website workflow as complete only when all of the following are true:

1. A concrete `webHero` target node exists for final code. If the flow does not already contain one, create it with `canvas_create_webhero_node`.
2. Section-level webpage preview screenshots exist as real image nodes.
3. The preview set has been confirmed by the user, or the current thread contains explicit approval for that exact preview set.
4. A prior asset inventory exists before codegen: `visibleSubjectInventory` plus flat `webPageAssetRequirements.visualSlots`, with one slot for each preview-visible non-text subject that needs implementation and at least one slot whose direct `previewNodeId` matches every approved preview.
5. A persistent `webPagePreviewVisualSpecs` array exists before asset planning, with one implementation-grade visual spec per approved preview. Each image asset slot must bind to that visual spec through `visualSpecId`, `visualSpecSummary`, or `sourceEvidence`.
6. Every `image_asset` slot is resolved before codegen. Slots marked `generate` or narrative/product/lifestyle/UI image slots must have a real canvas image node preserving page/asset/slot identity and a browser-usable `imageUrl`; their `webPageResolvedAssets` ledger entries persist `assetId` plus the exact generated `sourceNodeId`, never a copied internal URL. Searched/reused external assets persist their browser-usable URL directly.
7. Final code is written to `webHeroHtml`, `webHeroCss`, and `webHeroDocumentHtml` on the target `webHero` node, never into a text node.
8. Every approved preview screenshot is represented by a real final DOM `<section data-preview-node-id="...">`.

## Sub-Agent Delegation

The root agent is the orchestrator: it owns Runtime Stage decisions, the style/preview confirmation gates, pre-code evidence persistence, and final delivery summary. The subtasks below are independent and context-heavy and **MUST be delegated to sub-agents** via the `Agent` tool — running any of them inline on the root is a delegation regression. The root agent runs only the orchestration spine (stage decisions, gate decisions, contract persistence, final reply); every search, every preview/asset image generation, every consistency/fidelity check, and final WebHero code generation/commit goes through a sub-agent dispatch. Delegation never bypasses the existing gates (style selection, preview approval, codegen prep).

`explore` (sync, read-only fact gathering) — **MUST be dispatched** for every search call:

- Style / icon / web_asset searches: `canvas_web_style_reference_search`, `icon_search`, `web_asset_search`, `font_recommendation_search` (used in stages 2, 13). Return candidate URLs and metadata to the root agent; do not pick or write canvas.
- Reading existing canvas state: list current `webHero` / preview / asset node IDs and completion/ownership evidence, surface what's already resolved vs missing. Internal media is handed off by `sourceNodeId`; do not copy its hidden `imageUrl`.

`plan` (sync, `Skill`-only whitelist, pure synthesis output) — **MUST be dispatched** for stages 11–12 synthesis:

- Section plan + visual spec + asset slot inventory derivation: `webPageReferencePrompt`, `webPageImplementationBrief`, `fontPlan`, `previewDetailChecklist`, `webPagePreviewVisualSpecs`, `componentReferencePlan`, `visibleSubjectInventory`, flat `webPageAssetRequirements.visualSlots` (stages 11–12).
- Resolving search-backed slots into a `webPageResolvedAssets` proposal for searched/reused URLs (stage 13, search half) — the root agent or a media sub-agent persists the result.
- Final delivery summary: collect node ids, asset URLs, code character counts, failures into a human-readable handoff.
- **The synthesis OUTPUT for stages 11–12 MUST come from a real `Agent({subagent_type:"plan"})` dispatch.** Even though the root agent (not the plan sub-agent) is the one calling `canvas_update_node_data` to persist the result, the brief content itself — `webPageReferencePrompt`, `webPageImplementationBrief`, `fontPlan`, `previewDetailChecklist`, `webPagePreviewVisualSpecs`, `componentReferencePlan`, `visibleSubjectInventory`, and the flat `webPageAssetRequirements.visualSlots` — must be authored by the plan sub-agent and copied verbatim into two ordered persistence calls: first the six stage-11 `preview_visual_spec` fields, then the stage-12 `asset_inventory` fields. Never combine those two phases in one `patchNodeData[].data` item. Doing the synthesis inline in the root agent's own Thinking block / reasoning and only delegating the final write is forbidden: the value of the plan sub-agent is the dedicated synthesis context, not the persistence verb. If the plan dispatch fails with infra errors (Cloudflare 5xx, timeouts, `sub-agent 执行失败：LLM 请求失败`) two times in a row, STOP and fail loudly to the user — do not author the brief inline as a fallback.

`media` (generation dispatcher) — **MUST be dispatched** for stages 8–9 and 13 generation:

- Section preview screenshots: dispatch the `media` sub-agent synchronously so it must return only after `canvas_image_generate_to_canvas` has created/updated the preview image nodes and `canvas_image_wait_for_result` has resolved every preview node to `success` or a clear `failed/timed_out` status. Do not use `run_in_background:true` for this phase. The root must not advance to preview review, asset planning, or final code while any preview node is merely `queued`/`running`; if generation is still pending, return a waiting summary that names the pending node/task IDs.
- `generate`-marked `image_asset` slots: per-slot `canvas_image_generate_to_canvas`, preserving page/asset/slot/preview/visualSpec identity through fields currently supported by the tool schema (stage 13, generate half). Do not batch all page assets into one sub-agent; one generated image slot should normally be one `webhero_asset_generator` dispatch so failures and fidelity issues stop at the cheapest breakpoint.

`critic` (sync, multimodal evaluation) — dispatch only at the two visual gates below; do not add per-tool or per-section critic checks:

- Style / brand consistency check across the approved preview set before the asset stage. Inline self-review (a Thinking-block `verdict` JSON or any other root-agent self-judgment) is NOT a substitute and is forbidden — the consistency verdict must come from a real `Agent({subagent_type:"critic"})` dispatch.
- If the preview critic returns `needs_revision`/`fail` for only a subset of preview nodes and those nodes are regenerated, the follow-up critic dispatch must be scoped to the regenerated node IDs plus the minimal neighboring/context preview IDs named in the original issue. Do not reread the entire preview set after a targeted fix unless the original issue was global style inconsistency. Persist the earlier passing node reviews and merge them with the targeted follow-up verdict.
- Asset-vs-preview fidelity check after generate-half resolution: run one batched critic review for the generated assets against their owning approved preview screenshots. Do not call critic once per asset or after every normal canvas write.
- **Critic infra failure must fail loudly, not silently fall back.** If two consecutive `Agent({subagent_type:"critic"})` dispatches for the same review fail with infrastructure errors (Cloudflare 5xx such as 524, LLM provider timeouts, or `sub-agent 执行失败：LLM 请求失败` messages), STOP the WebHero workflow and return a final reply to the user that explicitly names the critic failure and the affected stage. The critic verdict (`pass` / `fail` / `needs_revision` or any equivalent shape) MUST come from a real `Agent({subagent_type:"critic"})` dispatch and from no other source. The following are explicitly forbidden as substitutes when the critic dispatch is failing: (a) root-agent media reads via `canvas_read_node_media_for_context` followed by internal judgment; (b) any other root-agent multimodal / evaluation tool that returns a verdict-shaped output, including but not limited to `canvas_evaluate_node`, `canvas_image_evaluate`, `canvas_visual_compare`, or any future tool whose output the root agent could read as `pass`/`fail`/`needs_revision`; (c) Thinking-block self-judgment serialized into a verdict JSON; (d) persisting a `webPageWorkflowContract.stepStatus` such as `critic_unavailable_proceeding_with_runtime_self_check` / `proceeding_without_critic` / `runtime_self_check_*` or any similar marker that implies the root agent supplied the verdict. Surfacing the critic failure to the user is the required exit; do NOT advance to stages 11–18 codegen, do NOT advance to asset generation, and do NOT mark any stage `verified` on the basis of root-agent self-inspection. Resuming requires either the critic infra recovering (third dispatch returning a real verdict) or explicit user instruction to override. A generic continuation such as "继续", "继续做", or "继续生成" is NOT override authorization; override requires explicit language such as "跳过 critic/跳过评审/允许绕过质检继续".

Final WebHero section-draft orchestration — **root/main owns stages 16–19**:

- Read current canvas state, the target WebHero contract, approved preview node IDs, resolved assets, retrieval records, and the `web_generation_codegen_prepare` diagnostic contract.
- Do not dispatch the coarse `codegen` sub-agent for WebHero final-code retries. It is too long-running for breakpoint debugging because it can wrap all section_codegen calls inside one bridge request.
- Step 1, section generation: root/main compares `sectionCodegenContract.sections` with existing `targetNode.data.webPageSectionDrafts`, then dispatches `section_codegen` only for missing or invalid sections with `result_mode:"full"`. Each dispatch must include a scoped `task_contract` with `kind:"webhero_section_codegen"`, `targetNodeIds:[<target WebHero node id>]`, `contextNodeIds:[<that section's approved preview node id>]`, and `allowedNodeIds` containing exactly those two identities, plus the section order, section id, visual slots, the emitted `assetId -> url` map, required embedded asset ids, global font/motion/detail tokens, and a clear instruction that preview screenshot URLs are reference-only and must not be embedded. For internal canvas assets the emitted `url` is exactly `{{asset:<sourceNodeId>}}`; pass and embed it verbatim, because commit resolves it server-side.
- Step 1 morphology rule: every `section_codegen` dispatch must tell the sub-agent to inspect the approved preview before styling media. Only create a card/panel/frame when the preview visibly places that exact subject inside a rounded/square card, bordered frame, shadowed tile, or glass panel. If the preview shows a transparent/cutout/background-matched/masked/full-bleed/inline asset, place the media directly and do not add an invented card, border, drop shadow, white box, glass tile, or generic `ImageCard`/`ProductCard`.
- Step 2, section-draft persistence: after each section draft returns successfully, root/main immediately upserts the exact full structured output into the target WebHero top-level field `webPageSectionDrafts`; the runtime replaces any model-supplied provenance with content-bound `codegenProvenance`. Do not hand-author, edit, normalize, or alias-convert the draft, and do not wait for every section to finish before the first persistence write. Each item must include `sectionId`, `previewNodeId`, `order`, `html`, `css`, `usedAssetIds`, `usedAssetUrls`, `motionHooks`, `consistencyNotes`, and `blocked`. A timed-out, failed, blocked, null-output, partial, or legacy alias-only result is not a draft: rerun only that section and never persist a fallback. Re-read the target node and verify one provenance-valid draft covers every approved preview before merge.
- Step 3, unified merge/check: after persisted section drafts are verified, root/main must call `canvas_webhero_check_readiness` for the target and continue only when its real backend result is `data.ready=true`; then dispatch exactly one `webhero_merge_codegen` sub-agent with the compact `mergeCodegenContract` emitted by `web_generation_codegen_prepare`. Copy the readiness identity into `task_contract:{kind:"webhero_merge_codegen",targetNodeIds:[targetWebHeroNodeId],sectionDraftsPersisted:true,persistedDraftCount:<previewNodeCount>,approvedPreviewNodes:<exact previewNodeIds>,flowUpdatedAt:<exact readiness flowUpdatedAt>,codeInputDigest:<exact readiness codeInputDigest>}`. Count-only matching is forbidden: the runtime requires the exact preview ID set, flow revision, and canonical style/spec/asset/draft digest, consumes that readiness result once, and serializes merge dispatches. Run a new readiness check before any later merge attempt. Do not pass the full uncompressed contract, full candidate ledgers, or long prose prompt addenda unless a field is genuinely missing from the compact merge contract. The merge sub-agent is the only final-code writer.
- Return the merge sub-agent's committed target node id, session id, preview-to-section map, consistency fixes, motion hooks, and used asset URLs. If any section lacks a required asset URL or returns blocked, return blocked instead of drafting generic fallback code.

Rules that delegation must respect:

- Delegate final WebHero code commit only to `webhero_merge_codegen`. The root agent owns section_codegen orchestration, section draft persistence, validation, and final reply.
- Never let a sub-agent run section preview image generation before the target webHero's `webPageWorkflowContract.selectedStyleReference` has been persisted and then verified by a fresh `canvas_flow_get` (whether selected via `ask_user` or auto-decided per stage 3). Dispatch with the single canonical `task_contract.kind="webPreview_generation"`, one target WebHero node ID, and `flowUpdatedAt` copied exactly from that read. Any later canvas write invalidates the read and requires another `canvas_flow_get` before dispatch.
- If style search returns degraded/empty, do not dispatch a `media` sub-agent for previews — surface the search failure per the Style Reference Selection Gate.
- After dispatching a `media` sub-agent, advance the Runtime Stage only from real completed node evidence: every required preview node must have a browser-usable URL and `success` status before preview review. Do not treat "sub-agent started", submitted task IDs, or `queued` sub-agent summaries as evidence of completed generation.
- Do not dispatch `critic` just to read an external style-reference URL from search results. External style URLs are selection metadata, not a hard multimodal gate; persist the selected card and derive the initial style bible from the search result title/metadata plus the user's requested style direction. The two critic gates are for real canvas preview/asset nodes after generation, where media is under JarvisHub control.
- If an upstream URL is missing, leave the dependent slot in `blocked`; do not invent a substitute prompt.
- `plan` whitelist is `Skill` only; do not let it call `canvas_*` / `*_search`. `explore` is read-only; do not let it write canvas.

## Runtime Stages

1. Create or reuse one concrete `webHero` target node and initialize `webPageWorkflowContract` on it. The contract is the short persistent source of truth and must include `currentStep`, `stepStatus`, `selectedStyleReference`, `sharedStyleBible`, `approvedPreviewNodes`, and `missingItems`.
2. Run `canvas_web_style_reference_search` before any WebHero webpage preview generation.
3. Present style reference candidates and choose a direction before generating previews. If style search returns usable image candidates, the root agent must call `ask_user` with visual `optionCards` and wait for the user's choice. The root agent may auto-select only when the user explicitly asks the system to choose for them in the current request (for example, "你直接选一个风格"). A named category such as "Awwwards 风格" is a search direction, not permission to skip visual selection.
4. Choose 5 visually distinct real results and call `ask_user` with `optionCards`. Each card must include `value`, `imageUrl`, `thumbnailUrl`, `title`, and `displayValue`. Use `value` for the machine-readable selection payload, and set `displayValue` to a short text such as `已选择风格参考：B` so the chat never shows a raw URL as the user's visible reply. Do not create canvas reference image nodes, do not create a `网页风格参考候选` group, and do not list source/page/image URLs as text for the user to copy. The UI renders clickable thumbnails and lets the user enlarge the real image.
5. If style search returns `degraded` or empty results, stop the WebHero preview workflow and report the search failure. Do not create generated fallback style boards, do not call image generation to invent references, and do not continue into section preview generation.
6. Style reference candidates must come from real search results or existing real URLs. Generated images are allowed later for webpage assets, but never as fake public style references.
7. Only after the user chooses a candidate, or after an explicit user instruction to auto-select has been honored, persist that choice as a canonical object in `webPageWorkflowContract.selectedStyleReference`: include `title` and at least one public, model-executable HTTP(S) `imageUrl`, `originalImageUrl`, or `vendorReferenceImageUrl`; a bare URL string, metadata-only object, local/private-only URL, or text-only custom description is invalid. The exact `canvas_update_node_data` call that changes `selectedStyleReference` must also pass `webHeroResetDownstreamEvidence:true`, and it must not write specs, assets, briefs, checklists, or section drafts in that same transition call. Derive `sharedStyleBible` from the search result title/source/metadata, the user's requested style direction, and the selected card's fit reason. Later step-status patches must be partial and must not resend `selectedStyleReference`. Immediately call `canvas_flow_get`, verify the exact target node contains that canonical persisted object, and copy that read's exact `updatedAt`. Do not mutate the canvas between this verification read and preview-media dispatch. The backend stamps each preview with the exact selected-style URL identity; changing the selection atomically clears prior approval/spec/asset/draft/final-code evidence. Do not block the workflow on reading external Pinterest/Bing image URLs with critic; those hosts are often slow or TLS-fragile. The generated preview screenshots become the first hard multimodal evidence and must be evaluated by critic after they exist on canvas.
8. Dispatch preview media only with `task_contract.kind="webPreview_generation"`, `targetNodeIds=[<the one WebHero node>]`, and `flowUpdatedAt=<the exact fresh canvas_flow_get updatedAt>`, then generate section-level webpage preview screenshots separately with `canvas_image_generate_to_canvas`. Every `canvas_image_generate_to_canvas` call with `purpose.kind="webPreview"` must include `purpose.forNodeId=<target WebHero id>`, `purpose.sectionId=<unique section id>`, and `purpose.order=<contiguous 1..N order>`; missing identity fails before image generation. Do not pass any Flow revision on the image call: the backend reads the target node's current persisted `selectedStyleReference` at generation time, so a preview call never needs a flow snapshot and is never rejected for an unrelated concurrent write. Never pass `purpose.slotId` for `webPreview`; `slotId` is reserved for `webPageAsset`. The server maps section/order atomically to `webScreenshotSectionId`/`webScreenshotOrder` in the generated node, so do not add a post-generation metadata patch. The runtime rejects alternate kind spellings and missing persisted-style evidence before starting the media sub-agent. Every preview node must preserve preview-to-webHero identity, 16:9 aspect intent, and approx 700×394 canvas node dimensions. Do not request 2K/4K by default: WebHero preview screenshots and generated webpage assets should omit `resolution` unless the user or active image model configuration explicitly requires a higher tier. The backend defaults WebHero APIMart/GPT-Image-2 preview and webpage asset generation to 1K to control cost; Gateway may require 2K for non-square aspect ratios because of its minimum pixel budget.
9. Wait for every preview node with `canvas_image_wait_for_result` before asking for confirmation.
10. Confirm the preview set before moving to the asset/reference stage. If the previews satisfy the style bible the root agent persisted in stage 7 (every preview node returned `status="success"`, the section order matches the planned layout, and the style critic dispatched per the Sub-Agent Delegation rules returns `verdict="pass"` for visual fidelity / style system / section order / codegen readiness), the root agent self-confirms and advances to stage 11; do not call `ask_user`. Only call `ask_user` if the critic returns `fail`/`needs_revision`, if any preview node failed, or if the user's request explicitly asks for manual confirmation. Persist any change to `webPageWorkflowContract.approvedPreviewNodes` in its own `canvas_update_node_data` transition with `webHeroResetDownstreamEvidence:true`; do not include new specs/assets/drafts in that call, and do not resend the approved set in later partial status patches. Preview approval — whether self-confirmed or user-confirmed — never authorizes immediate final code generation.
11. After preview approval, extract and persist implementation-grade reference context before any asset resolution or code staging. In one `preview_visual_spec` call write exactly `webPageReferencePrompt`, `webPageImplementationBrief`, `fontPlan`, `previewDetailChecklist`, `webPagePreviewVisualSpecs`, and `componentReferencePlan`; do not include stage-12 inventory fields in that call. `webPagePreviewVisualSpecs` is the persistent goal contract for screenshot-to-code fidelity: one item per approved preview, each with `visualSpecId`, `sectionId`, `previewNodeId`, `order`, `layoutSkeleton`, `mediaPlacement`, `typographyHierarchy`, `motionIntent`, `requiredDomArtifacts`, and `requiredCssArtifacts`.
12. In a separate later `asset_inventory` call, create the prior asset inventory before search/generation on the target WebHero node top-level: write `visibleSubjectInventory`, flat `webPageAssetRequirements.visualSlots`, and `webPageAssetDecisions`; do not resend any stage-11 field. Every approved preview must have at least one flat slot with its exact direct `previewNodeId`; nested/group-level ownership or `sourceEvidence.previewNodeId` alone does not satisfy preview coverage. Each slot must directly include `sectionId`, `previewNodeId` or `screenshotOrder`, `subjectId`, `slotId`, `description`, `implementation`, `assetId`, `renderMode`, `status`, `intendedWebUsage`, and for `image_asset` slots a `visualSpecId` or `sourceEvidence` linking it to the owning `webPagePreviewVisualSpecs` item. `intendedWebUsage` must include `surfaceTreatment` and `cardPolicy`: use `carded_panel` only when the approved preview visibly puts that exact subject inside a card/panel/frame; otherwise use `transparent_cutout`, `background_matched_media`, `masked_media`, `full_bleed_media`, or `inline_icon` and set a no-card policy. Preview-visible product, device, hardware, hero object, camera, hinge, screen, lifestyle, portrait, or scene subjects are real `image_asset` slots by default and must be searched/generated/resolved as browser-usable media; do not mark them `code_procedural` or `reference_only` to avoid asset generation. Reference-only procedural slots are allowed only for abstract layout evidence such as card grids, typography, decorative light, line work, or simple UI structure where no concrete product/person/scene image is meant to appear. Do not write grouped `{ slots: [...] }` records. Do not store the asset inventory only in a text node, only in `webPageWorkflowContract`, only in `webPageImplementationBrief`, or under aliases such as `flatPreCodeInventory`; the server gate accepts the exact target-node path `webPageAssetRequirements.visualSlots`.
13. Resolve every slot after the inventory exists. Search first for reusable/icon assets where appropriate, but if an `image_asset` slot is preview-visible, narrative/product/lifestyle/UI/foreground/background media, or has `implementation=generate`, it must be backed by a real generated canvas image node before final code. Persist exactly one ledger record per resolved slot: external searched/reused media uses `{ assetId, url, ... }`; internal generated media uses `{ assetId, sourceNodeId, status: "resolved", ... }`. Never invent `@asset:` aliases, never copy a hidden internal `imageUrl`, and never put `sourceNodeId` under `webPageWorkflowContract`.
14. In the WebHero webpage-code workflow, webpage assets are mandatory. Do not write plans or decisions that say "no additional image assets", "all visuals are procedural", or "no generated assets needed" for the page as a whole. `generatedAssets` in `webPageAssetDecisions` must reflect actual webpage asset work, not an emptyReason shortcut. Only abstract decorative/layout-only micro-elements may remain procedural; the workflow itself still requires real webpage asset generation/resolution.
15. Persist asset decisions as structured data on the target webHero node by writing `webPageAssetDecisions` with five required sections — `icons`, `searchAssets`, `generatedAssets`, `fontPlan`, `stylePlan`. `generatedAssets` must describe actual webpage asset generation/resolution work for this page; it must not be used as a blanket emptyReason escape hatch for the whole webpage. `stylePlan` should summarize the selected style reference / sharedStyleBible into inspectable records (palette, typography feel, composition cues, material/motion cues, or the compact style prompt itself). Do not create a separate canvas group for this evidence; the canvas renders a "网页资产规划" panel automatically from these fields plus child asset nodes.
16. Before final codegen, call `web_generation_codegen_prepare` as a hard WebHero contract compression step. If its `readiness.canWriteFinalCode` is false, stop at the named breakpoint and fix only the missing evidence; do not dispatch section_codegen or merge. `missingCriticalInputs` for `webPagePreviewVisualSpecs`, `visualSlots.imageAssetSourceEvidence`, unresolved image assets, preview-derived assets, or asset decisions are blocking errors, not soft warnings.
17. When `webhero_debug_resume_plan.nextAction=dispatch_codegen_only`, root/main calls `web_generation_codegen_prepare`, reads `sectionCodegenContract.sections`, compares them against existing `webPageSectionDrafts`, and directly dispatches one `section_codegen` sub-agent only for each missing or invalid section with `result_mode:"full"` and `task_contract.kind="webhero_section_codegen"`. Do not wrap all section generation inside the coarse `codegen` sub-agent.
18. Each `section_codegen` must read exactly its scoped preview screenshot through `canvas_read_node_media_for_context`, treat that screenshot as the section acceptance target, and output a local JSON draft `{ html, css, usedAssetIds, usedAssetUrls, motionHooks }`. When a section has embedded `image_asset` requirements, it must use the exact `resolvedAssets[].url` value rather than a preview screenshot URL; for internal canvas assets this is the canonical `{{asset:<sourceNodeId>}}` token and must remain unchanged through section draft and merge staging. Pure `code_procedural` / `reference_only` slots can be implemented as HTML/CSS without media references. Missing required resolved references are a blocked state, not permission to redraw products/devices/scenes with SVG/CSS. It must preserve the preview's media surface morphology: do not wrap direct media in a new rounded rectangle/card/shadow layer unless the preview and visual slot both say the subject is carded.
19. After each section draft returns, root/main immediately upserts it into the target WebHero field `webPageSectionDrafts`; this is the breakpoint artifact that prevents rerunning successful sections after a later timeout. After all required drafts are persisted, re-read the node and verify one non-blocked persisted draft exists for every approved preview. If persistence or coverage verification fails, stop and return blocked; do not continue to merge.
20. When `webhero_debug_resume_plan.nextAction=dispatch_merge_only`, root/main merges and submits final code by dispatching exactly one `webhero_merge_codegen` sub-agent. After the required readiness call, build the task contract from its exact `previewNodeIds`, `flowUpdatedAt`, and `codeInputDigest`; never reuse an earlier readiness result. Feed the sub-agent persisted section drafts plus the compact `mergeCodegenContract` from `web_generation_codegen_prepare`, so merge acts as an assembler/checker rather than a second full-page generator. The merge sub-agent must combine all section drafts, enforce one global font/token/nav/tab/header/motion system, verify every approved preview maps to one final `<section data-preview-node-id="...">`, verify every embedded `image_asset` external URL or canonical asset token appears in final HTML/CSS, and preserve section-draft media surfaces without inventing new card wrappers. Stage only `webHeroHtml` and `webHeroCss` on one stable `sessionId`; every stage call must copy the exact readiness `flowUpdatedAt`, `previewNodeIds`, and `codeInputDigest`, and `webHeroDocumentHtml` is a server-derived canonical field rejected by staging. Do not mutate codegen inputs between readiness, staging, and commit. After both staged fields are complete, call `canvas_webhero_code_commit`; the server resolves every `{{asset:<sourceNodeId>}}` only after complete chunk assembly, derives the document, and atomically persists the materialized code plus durable session state. If the response is lost or times out, retry the same commit with the same `sessionId`: it returns idempotent success only when the persisted node code exactly matches that committed session. Never create a second session as a retry and never patch final code through generic canvas tools. A readiness snapshot mismatch invalidates the transaction and must be surfaced; it is not permission to reuse stale chunks or bypass the gate. A confirmed or idempotent commit success is the terminal step.

## Style Reference Selection Gate

- Never call section preview image generation until a fresh `canvas_flow_get` proves the target `webHero` node has canonical `webPageWorkflowContract.selectedStyleReference`; top-level aliases and `sharedStyleBible` are not authorization evidence. Use canonical `task_contract.kind="webPreview_generation"` and copy that read's exact `updatedAt` into `flowUpdatedAt`.
- Search degraded/empty is not approval to continue into preview generation, and it is not approval to generate fake style references.
- If search is degraded/empty, stop and report the search failure with the provider warnings. The next action is to repair search or adjust search terms/source, not to generate images.
- After the user chooses a style candidate, update the contract first, then generate section previews. The preview prompt must cite the selected reference and the derived shared style bible.
- If the user chooses custom style instead of a candidate, require an uploaded/public model-executable reference image. A text description may supplement `sharedStyleBible` but cannot by itself become `selectedStyleReference`; do not generate previews until the canonical object contains a real image URL.

## Post-Approval Gate

When the user replies with approval such as "采用这组预览，继续生成最终官网代码", interpret that as permission to enter the asset/reference stage, not permission to write final code immediately.

Immediately after preview approval, the first todos must be about reading the flow, identifying approved preview nodes, extracting the implementation reference prompt/brief, planning component references, planning assets, and resolving or generating assets. Do not create todos named "构建 HTML/CSS", "写最终代码", or "提交 webHero 代码" until the evidence below exists on the target `webHero` node.

Required evidence before `canvas_webhero_code_stage_chunk`, `canvas_webhero_code_commit`, or any `canvas_update_node_data` that writes `webHeroHtml`, `webHeroCss`, or `webHeroDocumentHtml`:

- `webPageReferencePrompt`
- `webPageImplementationBrief`
- `fontPlan` or `webPageImplementationBrief.fontPlan`
- `previewDetailChecklist` or `webPageImplementationBrief.previewDetailChecklist`
- `webPagePreviewVisualSpecs`, one item per approved preview
- `componentReferencePlan` with real retrieval records/section decisions, or explicit per-section `write_from_scratch` decisions with implementation notes
- `visibleSubjectInventory` and `webPageAssetRequirements.visualSlots` as a flat pre-code inventory, not grouped slots and not post-gate patch data; each `image_asset` slot must carry `visualSpecId` or `sourceEvidence`
- `webPageResolvedAssets` with browser-usable URLs for external searched/reused assets and exact `sourceNodeId` references for generated canvas asset records
- Real canvas image nodes for every generated/narrative `image_asset` slot, carrying matching page/asset/slot identity
- `webPageAssetDecisions` with five sections (`icons`, `searchAssets`, `generatedAssets`, `fontPlan`, `stylePlan`); `generatedAssets` is a non-empty array of real `{ assetId, slotId, sourceNodeId | generatedNodeId, ... }` records, while the other sections are non-empty decision arrays or `{ emptyReason }`

`canvas_webhero_check_readiness` is a hard final-code gate, not an advisory diagnostic. Root must call it immediately before the single merge dispatch, copy its exact `previewNodeIds`, `flowUpdatedAt`, and `codeInputDigest` into the merge contract, and continue only when `data.ready=true`. If it returns `ready=false`, any `missing` item, or a tool error, return blocked and repair that exact persisted evidence; do not dispatch merge, stage code, or commit.

Forbidden immediately after preview approval:

- Calling `canvas_read_node_media_for_context` as a shortcut into codegen.
- Calling `canvas_webhero_code_stage_chunk` or `canvas_webhero_code_commit` from the root agent.
- Writing `webHeroHtml`, `webHeroCss`, or `webHeroDocumentHtml` in the same patch that first writes the reference prompt or implementation brief.

## Preview-Derived Asset Resolution

After preview approval, inspect each preview as an implementation target and decide assets at the moment they are needed:

- Icons, arrows, spec symbols, dock controls, configurator controls, badges, and tiny UI glyphs: call `icon_search` first. Use existing icon sets such as lucide, tabler, ph, mdi, or meteocons. If SVG/vector metadata or license/dimensions are needed, call `web_asset_search` too. Do not hand-write SVGs from memory.
- Fonts: extract the preview's typography feel into `fontPlan`, including display/body font names, loading URL if external fonts are used, fallback stack, and usage notes. Put the font plan on the asset board.
- Public/reusable images: for broad backgrounds, abstract plates, architecture, people, lifestyle, product atmospheres, and generic scene media, search reusable public/Aura assets first and record accepted/rejected candidates.
- Generated images: for precise branded/product hero images, single isolated transparent cutouts, device/watch/car cutouts, unusual crops, or motion state variants, first record the flat slot, then search if search could realistically satisfy the slot. If search fails quality, transparency, license, crop, or relevance checks, call `canvas_image_generate_to_canvas` for the same `assetId`/`slotId` before final code. Set `transparentPng=true` only for one isolated foreground object/logo/sticker/product with no background plate that must layer over live HTML/CSS. Do not request transparency for full hero scenes, illustration clusters, dashboards, maps, background art, or composed section artwork; generate those as embedded images with a matched background. A failed or unsuitable search is not a terminal state.
- For every generated image prompt, carry the slot's `intendedWebUsage.surfaceTreatment/cardPolicy`. If the approved preview does not visibly show a card/panel/frame around that subject, the prompt must explicitly say: no rounded rectangle, no square card, no border, no drop shadow, no white box, no glass tile, no framed image container. This prevents image models from baking a fake card into assets that should be cutouts, matched-background media, masked planes, or full-bleed media.
- Generation is mandatory for any slot whose final decision is `implementation="generate"` and for narrative/product/lifestyle/UI image slots that do not have an accepted searched URL. The generated node must reuse the slot's `assetId` and `slotId`; do not create a generic card image and later rename it.
- Every resolved asset must include a source audit: existing canvas checked, public/icon search checked, candidate URLs or record ids, rejection reasons when generating, and final decision.

## Asset Decisions (Structured Field)

Before final code, surface asset reasoning as structured data on the webHero node. Write `webPageAssetDecisions` with five sections:

- `icons`: array of `{ iconId, source, usage }` from `icon_search` / icon `web_asset_search` records.
- `searchAssets`: array of `{ url, source, decision: "accepted" | "rejected", reason }`.
- `generatedAssets`: array of `{ assetId, slotId, generatedNodeId, reason }`.
- `fontPlan`: array of `{ font, role: "display" | "body", url?, fallback?, usage }`.
- `stylePlan`: array of `{ title, usage, body?, prompt?, imageUrl?, url? }` summarizing the selected style reference and sharedStyleBible into inspectable palette / typography / composition / material / motion cues.

All sections other than `generatedAssets` may instead be `{ emptyReason: "<explicit reason>" }` when there is a real decision to leave them empty (e.g. all visible glyphs are CSS/text — record that as `icons: { emptyReason }`). Empty arrays without `emptyReason` are not accepted, and `generatedAssets` cannot use `emptyReason`. Generated image assets continue to live as canvas image nodes associated with the owning webHero; the structured field summarizes decisions, it does not replace the asset nodes. The canvas renders the "网页资产规划" panel automatically from this field; do not call any board-creation tool.

## WebHero Target Rules

- Use `canvas_create_webhero_node` once per website workflow when no target exists.
- Before creating a WebHero target, choose one stable explicit target identity, such as `webhero_<slug>_<shortid>`, using the current tool schema. Do not rely on validation errors to discover missing identity.
- Keep the target id stable and attach preview/assets metadata to that target when useful.
- Do not create a "final webpage" text node.
- Do not store HTML/CSS/JS in `content` or `prompt`.
- If internal generation produced `html`, `css`, and `documentHtml`, stage only `html`/`css` (or `webHeroHtml`/`webHeroCss`) through the WebHero code tools. Treat the internal document as a local verification artifact; the server derives canonical `webHeroDocumentHtml`. Do not write any final-code field with `canvas_update_node_data` or public flow patches.

## Embedded vs Reference-Only Assets

Each `image_asset` slot must declare whether its resolved URL is meant to be embedded in the final HTML/CSS or used only as a visual reference for procedurally-rendered code. The final-code gate enforces URL embedding by default, so reference-only intent must be explicit.

- **Embedded (default).** The resolved external URL or canonical `{{asset:<sourceNodeId>}}` token mu

…(truncated)
