.claude/skills/frontend/SKILL.md
Frontend standards for atopile extension webviews: architecture, contracts, design system, and testing workflow.
npx skillsauth add atopile/atopile frontendInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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
development
How the Faebryk parameter solver works (Sets/Literals, Parameters, Expressions), the core invariants enforced during mutation, and practical workflows for debugging and extending the solver. Use when implementing or modifying constraint solving, parameter bounds, or debugging expression simplification.
development
# SEXP Benchmark Strategy ## Goal Measure and improve S-expression pipeline performance with a focus on: - Throughput per stage - Peak memory per stage - End-to-end behavior on realistic KiCad PCB inputs ## Pipeline Stages Benchmark these layers separately: - `tokenizer` - `ast` - `parser` (typed decode) - `encode` (typed encode to raw SEXP) - `pretty` (formatting) ## Dataset Dimensions Use a matrix over: - `depth`: shallow vs deep nesting - `size`: small, medium, large Recommended size buck
development
How the Zig S-expression engine and typed KiCad models work, how they are exposed to Python (pyzig_sexp), and the invariants around parsing, formatting, and freeing. Use when working with KiCad file parsing, S-expression generation, or layout sync.
tools
How the Zig↔Python binding layer works (pyzig), including build-on-import, wrapper generation patterns, ownership rules, and where to add new exported APIs. Use when adding Zig-Python bindings, modifying native extensions, or debugging C-API interactions.