This brief explains how to extend the Logic Circuit Lab application that ships with the Bespoke generalized components. Use it as the single source of truth for project scope, file structure, and code style.
- Goal: Deliver an embeddable circuit playground that feels native inside any host site by relying on the
.bespokedesign system for UI consistency. - Client (
client/): Contains the HTML shell, Bespoke CSS, gate assets, logic simulator, help content, and integration tests (test-integration.html). - Server (
server.js): Node.js (CommonJS) server that serves static assets, handles VHDL exports, and relays/messagebroadcasts via WebSockets (wsdependency). - Utilities:
circuit-report.jssummarizes each VHDL export; data files such asinitial_state.jsonandgate-config.jsonseed the canvas and palette.
| Path | Purpose |
|---|---|
client/index.html |
Bespoke application shell (header, status, canvas, sidebar, help trigger). |
client/bespoke.css |
Core Bespoke framework — never edit variables here, only override. |
client/logic-sim.js |
Canvas rendering, drag/drop, wiring, simulation, persistence, exports. |
client/logic-sim.css |
Circuit-specific styling layered on top of Bespoke tokens. |
client/help-modal.js |
Help modal utility (import from all apps). |
client/help-content-template.html |
Source for modal copy; fetched at runtime. |
client/gate-registry.js, client/gates/*.svg |
Gate definitions, icons, logic functions. |
client/gate-config.json |
Palette order, export report toggles, default zoom, etc. |
client/initial_state.json |
Starter board loaded on first run or after reset. |
server.js |
Static server plus /vhdl/export and /message endpoints. |
Every embedded application must expose the following files (and keep them in this load order):
bespoke.csshelp-modal.jsapp.js(application logic)server.js
- Always apply the
.bespokescope (usually on the<body>or outermost<div>). - Use only the provided CSS custom properties for colors, spacing, typography, borders, and shadows:
- Colors:
--bespoke-bg,--bespoke-fg,--bespoke-accent,--bespoke-muted,--bespoke-box,--bespoke-danger, etc. - Spacing:
--bespoke-space-xs…--bespoke-space-2xl - Typography:
--bespoke-font-size-*,--bespoke-font-weight-* - Borders & radius:
--bespoke-stroke,--bespoke-radius-sm|md|lg|xl - Shadows:
--bespoke-shadow-sm|md|lg|xl
- Colors:
- Put overrides in app-specific files (e.g.,
logic-sim.css), never insidebespoke.css. - Name CSS files in kebab-case (
logic-sim.css,gate-palette.css). - Theme-specific tweaks should be implemented by overriding tokens on
.bespoke.
CSS example
.bespoke {
--bespoke-bg: #101217;
--bespoke-accent: #56ccf2;
}
.canvas-grid {
background-image: linear-gradient(var(--grid-color) 1px, transparent 1px);
box-shadow: var(--bespoke-shadow-lg);
border-radius: var(--bespoke-radius-lg);
}import HelpModal from './help-modal.js';
const helpCopy = await fetch('./help-content-template.html').then(r => r.text());
new HelpModal({
triggerSelector: '#btn-help',
content: helpCopy,
theme: 'auto',
});Use setStatus() and only these strings:
ReadyLoading...Saving...Changes savedSave failed (will retry)Failed to load dataAuto-save initialized
- Wrap every async workflow in
try/catch; log errors viaconsole.error. - Provide useful UI feedback inside
catchblocks. - Implement retry logic for network calls (e.g., exponential/backoff for
/vhdl/export). - Trap and handle
localStoragequota errors; keep the in-memory canvas running if persistence fails. - Validate data before writes (e.g., snapshot schema, gate payloads).
- Debounce saves, call
setStatus('Saving...'), and showChanges savedon success. - If a save fails, surface
Save failed (will retry)and schedule the retry.
GET /serves everything underclient/.POST /vhdl/exportexpects{ vhdl: string, state: object }, writesuser.vhdl+state.json, and triggerscircuit-report.js.POST /messagebroadcasts{"message":"..."}to all WebSocket clients (requiresws).- WebSockets become available automatically when
wsis installed; clients alert incoming messages. - Client exports are initiated via
window.logicSim.exportToVhdl(), alogic-sim:export-vhdlevent, or a parentpostMessage.
- Prefer ES modules in
client/(useimport/export), CommonJS inserver.js. - Use
const/let(novar). Default toconst. - Keep functions pure when possible; isolate DOM mutations.
- Always guard async calls with
try/catchand propagate meaningful errors. - Document non-trivial flows with short comments (avoid restating obvious code).
- Keep filenames in kebab-case (
logic-sim.js,help-modal.js).
export async function loadInitialState() {
setStatus('Loading...');
try {
const res = await fetch('./initial_state.json');
if (!res.ok) throw new Error('Starter circuit unavailable');
const state = await res.json();
setStatus('Ready');
return state;
} catch (error) {
console.error('[loadInitialState]', error);
setStatus('Failed to load data');
throw error;
}
}- Scope selectors under
.bespokewhenever the rule affects the shared UI. - Use spacing helpers instead of hard-coded pixels (
padding: var(--bespoke-space-lg)). - Favor utility classes from Bespoke before adding new ones; if you add custom classes, prefix them with the component name (
.canvas-toolbar,.palette-card).
.bespoke .palette-card {
display: flex;
gap: var(--bespoke-space-sm);
border: 1px solid var(--bespoke-stroke);
}- Keep semantics intact: use
<header>,<main>,<aside>,<section>,<button>,<form>, etc. - Preserve ARIA attributes and keyboard access (button elements instead of
<div>). - Reference scripts at the end of the body and maintain the documented order.
<header class="header">
<h1>Logic Circuit Lab</h1>
<div class="status" id="status">Ready</div>
<button id="btn-help" class="as-button ghost">Help</button>
</header>client/help-content-template.html— duplicate sections to document new tools or grading rubrics.circuit-report.js— adjust report toggles viaclient/gate-config.json.
Follow this playbook whenever you add new features, help content, or integrations so the Bespoke components remain consistent across every embedded deployment of Logic Circuit Lab.