frontend
Frontend standards for atopile extension webviews: architecture, contracts, design system, and testing workflow.
/plugin install atopiledetails
Frontend Skill
Use this skill when building or modifying frontend features in atopile.
Default target is extension webviews (ui-server + vscode-atopile).
Quick Start
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 localtsc && vite build../dev.sh: run backend + Vite for integration testing in browser.ato dev compile: build extension artifacts (default targetall).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.
Relevant Files
Main Extension Webview App
- Root:
src/ui-server/src/ - Transport:
src/ui-server/src/api/ - Global state:
src/ui-server/src/store/ - Feature hooks:
src/ui-server/src/hooks/ - Feature components:
src/ui-server/src/components/ - Shared components:
src/ui-server/src/components/shared/ - Utilities:
src/ui-server/src/utils/ - Styles/tokens:
src/ui-server/src/styles/ - Contracts:
src/ui-server/src/types/ - Tests:
src/ui-server/src/__tests__/
Extension Host Bridge
- Root:
src/vscode-atopile/src/ - Use for IDE commands/webview wiring/host integration.
- Keep core React UI logic out of this layer.
Specialized Standalone App Example
- Root:
src/atopile/visualizer/web/src/ - Use as reference for compute/canvas/worker patterns.
Layout Editor (Specialized)
- Root:
src/atopile/layout_server/frontend/src/ - Specialized layout editor frontend; not default architecture for webviews.
Dependants (Call Sites)
- Extension webviews are built from
src/ui-serverand loaded bysrc/vscode-atopile. ato dev compileandato dev installare the common extension developer loop.src/atopile/visualizer/webis a separate app and reference pattern, not default target.
How to Work With / Develop / Test
Typical Change Paths
Use these patterns to keep changes scoped and predictable.
- UI-only change (no contract changes)
- touch
components/,styles/, smallhooks/usage - avoid transport/store churn unless required
- validate through browser-first flow + focused component tests
- UI + state change
- add/adjust store fields/actions/selectors
- keep transport untouched if payload shape is unchanged
- add store transition tests and UI interaction tests
- UI + contract/transport change
- update Pydantic contracts first
- regenerate TS types
- update
api/mapping + store state transitions + UI - add transport and state tests, then browser flow validation
Architecture Standard
Default architecture:
- Backend: FastAPI (domain, APIs, events)
- Frontend: React + Vite
- Realtime: WebSocket-first transport
Layer boundaries:
api/: HTTP + WS transport and payload mappingstore/: typed app state, actions, selectorscomponents/: rendering/compositionutils/lib: pure transforms/logic
Contract Standard (Required)
Schema-first contract workflow:
- Define/modify backend Pydantic model.
- Regenerate frontend TS schema/types.
- Update frontend transport/store/components using generated types.
- Add/update tests for changed contract behavior.
Do not:
- maintain duplicate handwritten interfaces if generated types exist
- use stringly-typed protocol payloads when typed contracts exist
One-Flow Rule (Required)
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.
WebSocket Standard
Use WebSocket for:
- interactive state sync
- action dispatch + action results
- long-running workflow updates
Use HTTP for:
- bootstrap reads
- direct idempotent reads
- file/artifact retrieval
Required WS client behavior:
- reconnect with bounded backoff
- explicit connected/disconnected state in store
- pending request timeout/cancel handling
- post-reconnect resync
Recommended WS client behavior:
- centralize WS connection in
api/module - keep message decoding/type-guarding out of components
- record minimal telemetry/logging for reconnect and parse failures
- guard against stale async results when reconnecting
Example 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 };
};
Reuse Rules
Before creating new primitives:
- Check
src/ui-server/src/components/shared/. - Check
src/ui-server/src/utils/for existing logic. - If adding compute/canvas behavior, check
src/atopile/visualizer/web/src/lib/andsrc/atopile/visualizer/web/src/workers/. - If behavior is IDE-host specific, keep it in
src/vscode-atopile/src/.
Promote to shared when:
- used by 2+ feature surfaces, or
- repeated interaction semantics would drift if duplicated.
Shared Assets Reference
Shared Components (ui-server)
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.
Shared Utilities (ui-server)
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.ts
Specialized Utility Reference (visualizer)
Useful standalone reference:
src/atopile/visualizer/web/src/lib/exportUtils.ts
Best Practices
Frontend Code Quality
- Keep strict TS and typed state transitions.
- Isolate side effects in transport/hooks, not leaf components.
- Use selectors, not broad full-store subscriptions.
- Implement explicit loading/error/empty states.
Example 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;
}
Design System
Apply across all surfaces:
- host-native typography/colors first
- brand accents only where semantically useful
- complete interaction states (
default/hover/focus-visible/active/disabled/loading) - consistent spacing/row-height/typography rhythm
- tokenized colors/spacing/radius/z-index, no ad-hoc semantic hardcoding
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;
}
Accessibility Baseline
Required:
- keyboard-operable controls
- deterministic focus order
- ARIA only where native semantics are insufficient
- visible focus states
- readable contrast in light/dark modes
Performance Baseline
Required:
- memoize expensive derived data/callbacks in hot paths
- use
requestAnimationFramefor drag/resize animation paths - move heavy layout/geometry/compute work to workers where needed
- keep WS update handling efficient under active event streams
Operational checks:
- avoid full-store subscriptions in high-frequency components
- memoize derived collections used in render loops
- verify no avoidable setState chains during drag/scroll/update streams
- keep long-running transformations out of component render bodies
Implementation Playbooks
Playbook A: New Extension Webview Panel (ui-server)
- Add/confirm contracts
- if backend shape changes: update Pydantic + regenerate types
- Add transport mapping
- implement data/action methods in
src/ui-server/src/api/
- Add store state/actions
- add minimal new fields/actions in
store/ - expose selectors for component use
- Compose UI
- build panel in
components/ - reuse
components/shared/primitives where possible
- Validate
- run tests
- run browser-first flow
- capture screenshot + inspect ui logs
Playbook B: Compute/Canvas-heavy Feature
- Put core transforms into
utils/or specializedlib/module. - Add worker offload if main-thread latency becomes visible.
- Keep render components thin and memoized.
- Validate interaction smoothness under active updates.
Playbook C: Long-running Workflow UI
Use one canonical flow:
- trigger
- in-progress
- completion or error in same context
Required:
- disable conflicting controls during in-progress state
- emit progress updates via typed WS events
- provide deterministic terminal state in store
Detailed Testing Notes
Testing Scope by Layer
- Unit tests
- pure utils/lib transforms
- Store tests
- action transitions and derived selector correctness
- Transport tests
- API/WS mapping, error handling, request correlation behavior
- UI tests
- user interaction + state rendering behavior
- Browser automation checks
- key flow interaction + screenshot + ui logs
WebSocket Feature Test Cases
At minimum test:
- initial connect path
- disconnect state update
- reconnect and resync path
- pending request timeout/cancel path
Recommended:
- late or duplicate event tolerance
- malformed message handling without UI crash
Testing Standard
Minimum per feature:
- Store/action test
- API/transport test
- UI interaction test
- Error/loading/empty-state test
Example matrix (build queue):
- store: enqueue + complete transitions
- API: build start error -> typed API error
- UI: cancel click dispatches cancel action
- state: disconnected WS state is visible
Browser-First Dev Viewer Flow (Required)
Agents should self-test in browser flow first:
cd src/ui-server
./dev.sh
Then:
- Validate interaction flow in browser webview page.
- Capture key-state screenshots.
- Inspect UI logs.
- Fix issues.
- Ask user to test in extension host only after browser flow is clean.
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.html
Puppeteer + Vite Screenshot APIs
Use 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:
- stable selectors (
data-testidor semantic roles) - fixed viewport for diffs
- readiness-based waits preferred over arbitrary sleep
- runtime errors treated as failures unless allowlisted
Definition of Done
A feature is done only when all are true:
- one canonical flow implemented (no fallback branch)
- contract changes modeled in Pydantic + regenerated TS consumed
- WS behavior validated (connect/reconnect/resync)
- tests added/updated (store + transport + UI + state handling)
- browser-first dev viewer checks complete
- user asked to test extension host only after browser validation
- build/test commands pass for touched app
- component/util placement follows repo structure and reuse rules
PR Checklist (Copy/Paste)
- [ ] 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
technical
- github
- atopile/atopile
- stars
- 3177
- license
- MIT
- contributors
- 41
- last commit
- 2026-04-03T20:56:37Z
- file
- .claude/skills/frontend/SKILL.md