Frontend standards for atopile extension webviews: architecture, contracts, design system, and testing workflow.
cd ~/.claude/skills
git clone https://github.com/atopile/atopile.git atopile mkdir -p ~/.claude/skills/frontend
curl -fsSL https://raw.githubusercontent.com/atopile/atopile/HEAD/.claude/skills/frontend/SKILL.md \
-o ~/.claude/skills/frontend/SKILL.md Use this skill when building or modifying frontend features in atopile.
Default target is extension webviews (ui-server + vscode-atopile).
Dependency install:
cd src/ui-server
bun install
Frontend-only loop (no backend integration):
cd src/ui-server
bun run dev
bun run test
bun run build
Webview integration loop (backend + Vite):
cd src/ui-server
./dev.sh
Extension package/install loop:
ato dev compile && ato dev install cursor
# or
ato dev compile && ato dev install vscode
Command reference:
bun install: install/sync JS dependencies.bun run dev: start local Vite dev server (frontend-only iteration).bun run test: run local Vitest suite once.bun run build: run local tsc && vite build../dev.sh: run backend + Vite for integration testing in browser.ato dev compile: build extension artifacts (default target all).ato dev install cursor|vscode: install latest built extension .vsix.ato dev ui: open a webpage for the user showing the shared component library components.src/ui-server/src/src/ui-server/src/api/src/ui-server/src/store/src/ui-server/src/hooks/src/ui-server/src/components/src/ui-server/src/components/shared/src/ui-server/src/utils/src/ui-server/src/styles/src/ui-server/src/types/src/ui-server/src/__tests__/src/vscode-atopile/src/src/atopile/visualizer/web/src/src/atopile/layout_server/frontend/src/src/ui-server and loaded by src/vscode-atopile.ato dev compile and ato dev install are the common extension developer loop.src/atopile/visualizer/web is a separate app and reference pattern, not default target.Use these patterns to keep changes scoped and predictable.
components/, styles/, small hooks/ usageapi/ mapping + store state transitions + UIDefault architecture:
Layer boundaries:
api/: HTTP + WS transport and payload mappingstore/: typed app state, actions, selectorscomponents/: rendering/compositionutils/lib: pure transforms/logicSchema-first contract workflow:
Do not:
Implement one canonical user flow per feature.
Do not introduce fallback flow branches. If dependency/state is unavailable, surface a clear stop-state error in the same flow context.
Use WebSocket for:
Use HTTP for:
Required WS client behavior:
Recommended WS client behavior:
api/ moduleExample envelope shape:
type WsMessage =
| { type: "state"; data: AppState }
| { type: "event"; event: EventType; data: EventPayload }
| {
type: "action_result";
action: string;
requestId?: string;
result: { success: boolean; error?: string };
};
Before creating new primitives:
src/ui-server/src/components/shared/.src/ui-server/src/utils/ for existing logic.src/atopile/visualizer/web/src/lib/ and src/atopile/visualizer/web/src/workers/.src/vscode-atopile/src/.Promote to shared when:
Prefer reusing the components in src/ui-server/src/components/shared/ before creating equivalents.
If a new component is needed, create it in src/ui-server/src/components/shared/ and reuse it in the feature.
If possible, compose complex components from existing shared components.
Prefer extending these utilities:
src/ui-server/src/utils/codeHighlight.tsxsrc/ui-server/src/utils/nameValidation.tssrc/ui-server/src/utils/packageUtils.tssrc/ui-server/src/utils/searchUtils.tsUseful standalone reference:
src/atopile/visualizer/web/src/lib/exportUtils.tsExample typed API boundary:
export async function fetchBuilds(
projectRoot: string,
): Promise<BuildSummary[]> {
const res = await fetch(
`/api/builds?project_root=${encodeURIComponent(projectRoot)}`,
);
if (!res.ok) throw new APIError(res.status, "Failed to fetch builds");
const data = (await res.json()) as { builds: BuildSummary[] };
return data.builds;
}
Apply across all surfaces:
default/hover/focus-visible/active/disabled/loading)Example tokenized control:
.btn-default {
background: var(--accent);
color: var(--text-on-accent);
border: 1px solid var(--accent);
border-radius: var(--radius-md);
padding: 0 var(--spacing-md);
}
.btn-default:hover:not(:disabled) {
background: var(--accent-hover);
border-color: var(--accent-hover);
}
.btn-default:focus-visible {
outline: 2px solid var(--info);
outline-offset: 1px;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
Required:
Required:
requestAnimationFrame for drag/resize animation pathsOperational checks:
ui-server)src/ui-server/src/api/store/components/components/shared/ primitives where possibleutils/ or specialized lib/ module.Use one canonical flow:
Required:
At minimum test:
Recommended:
Minimum per feature:
Example matrix (build queue):
Agents should self-test in browser flow first:
cd src/ui-server
./dev.sh
Then:
Relevant pages:
http://127.0.0.1:5173/http://127.0.0.1:5173/log-viewer.htmlhttp://127.0.0.1:5173/migrate.htmlhttp://127.0.0.1:5173/test-explorer.htmlUse these built-in dev endpoints:
curl -sS -X POST http://127.0.0.1:5173/api/screenshot \
-H 'Content-Type: application/json' \
-d '{"path":"/","name":"default","waitMs":1200}'
curl -sS -X POST http://127.0.0.1:5173/api/screenshot \
-H 'Content-Type: application/json' \
-d '{"path":"/","name":"projects-expanded","uiActions":[{"type":"openSection","sectionId":"projects"}],"uiActionWaitMs":600}'
curl -sS http://127.0.0.1:5173/api/ui-logs
Automation guardrails:
data-testid or semantic roles)A feature is done only when all are true:
- [ ] Single canonical flow preserved (no fallback path added)
- [ ] Pydantic models updated for API/WS changes
- [ ] Generated TS schema/types regenerated and committed
- [ ] WS reconnect/resync behavior verified
- [ ] Browser dev viewer flow validated (`./dev.sh`)
- [ ] Screenshots + UI logs reviewed (no unapproved runtime errors)
- [ ] Added/updated: store test, transport test, UI interaction test
- [ ] Asked user to test in extension host only after browser checks passed You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation.
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
Use when receiving code review feedback, before implementing suggestions, especially if feedback seems unclear or technically questionable - requires technical rigor and verification, not performative agreement or blind implementation
Use when completing tasks, implementing major features, or before merging to verify work meets requirements
Use when starting feature work that needs isolation from current workspace or before executing implementation plans - ensures an isolated workspace exists via native tools or git worktree fallback
Use when starting any conversation - establishes how to find and use skills, requiring skill invocation before ANY response including clarifying questions