paperclipai/paperclip · error
Could not load wireframe viewer styles
Error message
Could not load wireframe viewer styles
What it means
Fail-fast guard in the v8 wireframe generator: the script cannot extract the viewer CSS block from the HTML template it is assembling the standalone wireframe viewer around, so it aborts instead of emitting a viewer with missing/unstyled presentation. Fires when the template file at the configured path is missing, unreadable, or no longer contains the style markers the generator scrapes.
Solutions
- Verify the template path passed to the generator exists and is readable.
- Re-add or update the expected style markers in the template after hand-editing the viewer HTML.
- Regenerate the template from the version the generator was written against (check git history of the plan file).
- If the template was intentionally restructured, update the style-extraction logic in the generator to match the new markers.
Defensive patterns
Strategy: fallback
When it happens
Trigger: Thrown at doc/plans/chat-adapters/generate-wireframes-v8.mjs:931 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/a4c96d2bf717205b.
Report an issue: GitHub.
Appendix: source
Thrown at doc/plans/chat-adapters/generate-wireframes-v8.mjs:931
`### ${screen.id} · ${screen.title}\n\nPurpose: ${screen.subtitle}\n\n${screen.annotations.map((item, index) => `${index + 1}. ${item}`).join("\n")}\n\n${screen.actions ? `Actions:\n\n${screen.actions.map(([label, effect]) => `- **${label}:** ${effect}`).join("\n")}\n\n` : ""}Rationale: ${screen.rationale}`,
)
.join("\n\n");
const permissions = permissionModel
.map(([name, behavior]) => `- **${name}:** ${behavior}`)
.join("\n");
return `# Paperclip Chat Adapters UI Surfaces — v8\n\nDate: 2026-09-04 \nOriginal planning base: \`${baseSha}\`; release qualification records the exact tested revision separately. \nReview viewer: [\`index.html\`](./index.html) \nWireframes: [\`wireframes-v8/\`](./wireframes-v8/)\n\n## Permission model\n\n${permissions}\n\n## Access tab\n\n**Settings answers where the bot may work. Access answers who an external sender represents and what Paperclip authority applies.** A linked external identity acts as its mapped Paperclip user and is checked against current permissions on every action. An unlinked identity may be allowed under the fixed restricted profile: it can converse within enabled resources and attach safe files, but it cannot approve, change budgets, hire, manage permissions or connections, or reassign agents. The connection owner remains an internal audit and authority ceiling; it is not ordinary UI configuration.\n\n## Conversations tab\n\nEach provider has one plain list. Every row contains the external conversation, Paperclip task, current state, an Open-provider link, and Open task. There is no separate binding-management section or conversation-boundary explainer. If provider access disappears, the row becomes unavailable while its history remains inspectable.\n\nThe former \"How conversations work\" screens are removed. Provider-native activation and reply behavior remains implementation documentation, not a standalone product page.\n\n## Screen inventory\n\n| ID | Group | Surface | Title | Desktop | Mobile |\n|---|---|---|---|---|---|\n${inventory}\n\n## Annotation and action notes\n\n${details}\n`;
}
function viewerHtml() {
const template = readFileSync(
join(
root,
"../../../packages/skills-catalog/catalog/bundled/product/wireframe/assets/site-template.html",
),
"utf8",
);
const style = template.match(/<style>[\s\S]*?<\/style>/)?.[0];
if (!style) throw new Error("Could not load wireframe viewer styles");
const toc = groups
.map(
([label, screens]) =>
`<h2>${esc(label)}</h2>${screens.map((screen) => `<a href="#s${screen.id}"><span class="num">${Number(screen.id)}</span>${esc(screen.title)}</a>`).join("\n")}`,
)
.join("\n");
const sections = groups
.map(
([label, screens]) =>
`<div class="provider-break"><div class="lede">${esc(label)}</div><h2>${label === "Start" ? "Shared connection start" : label === "Paperclip" ? "Shared Paperclip surfaces" : `${esc(label)} connector`}</h2></div>${screens
.map((screen) => {
const notes = screen.annotations
.map(
(note, index) => `<li><b>${index + 1}</b> — ${esc(note)}</li>`,
)
.join("\n");
const actions = screen.actions
? `<h3>What the actions do</h3><ul>${screen.actions.map(([name, effect]) => `<li><b>${esc(name)}</b> — ${esc(effect)}</li>`).join("\n")}</ul>`View on GitHub (pinned to 3f1d897a7c)