This repository contains the CodeSignal Probability Lab, a Bespoke simulation for repeated-trial probability experiments (coin, die, spinner, and configurable custom devices) that visualizes convergence.
The Probability Lab helps students understand:
- Sample space (all possible outcomes)
- Events (subsets of outcomes)
- Theoretical probability (what should happen in the long run)
- Experimental probability (what data shows)
- Convergence (estimates stabilize as trials increase)
- One event mode: event builder, live bar chart, convergence chart, frequency table
- Two events mode: joint heatmap + two-way table with joint/conditional reads
- Bias controls: fair vs biased devices (coin, die, spinner; custom devices are configured via
config.json) - Event relationships: independent, dependent
- Custom devices: define up to 50 outcomes + probabilities in
config.json
client/
index.html # App shell and layout
app.js # Main entry (store, config, runner, UI wiring)
app.css # App styling
help-content.html # Help modal content
config.json # Runtime configuration (dev default)
src/ # Modular ES modules
shell/ # help/config
shared/ # math + format utilities
probability-lab/ # domain/engine/state/ui
design-system/ # CodeSignal Design System assets (git submodule; treat as read-only)
agents.md # Design system deep reference (lowercase file)
dist/ # Production build output (vite build)
activity.log # Appends JSON lines from POST /log
package.json # Scripts + tool versions
package-lock.json # Lockfile
PLAN.md # Project plan / working notes
server.js # HTTP server for prod/API
vite.config.js # Vite root=client, dev proxy config
vitest.config.js # Vitest config
tests/ # Vitest suites (domain/engine/shared)
- Start dev servers (Vite on 3000 + API server on 3001):
npm run start:dev - Build for production:
npm run build - Start production server (serves dist):
npm run start:prod - Run tests:
npm test - Start Vite only:
npm run dev:vite - Start API server only:
npm run dev:api - Start production via alias:
npm start
- Dev uses
client/config.jsonserved by Vite. - Production serves
/config.jsonfromserver.jsusingCONFIG_PATH(default./config.json). - Config validation happens in
client/src/shell/config.js.
Supported config shapes:
Single mode:
{
"mode": "single",
"device": "coin",
"sections": {
"barChart": true,
"convergence": false,
"frequencyTable": false,
"history": false
}
}Single mode (custom device):
{
"mode": "single",
"device": "custom",
"deviceSettings": {
"name": "Exam",
"icon": "📚",
"outcomes": ["pass", "fail"],
"probabilities": [0.7, 0.3]
},
"sections": {
"barChart": true,
"convergence": true,
"frequencyTable": true,
"history": false
}
}Two-event mode:
{
"mode": "two",
"deviceA": "coin",
"deviceB": "die",
"sections": {
"jointDistribution": true,
"twoWayTable": true
}
}Two-event mode (custom devices):
{
"mode": "two",
"deviceA": "custom",
"deviceASettings": {
"name": "Weather",
"outcomes": ["sun", "rain", "snow"]
},
"deviceB": "custom",
"deviceBSettings": {
"name": "Traffic",
"outcomes": ["light", "medium", "heavy"]
},
"sections": {
"jointDistribution": true,
"twoWayTable": true
}
}Notes:
- Valid modes:
single,two. - Valid devices:
coin,die,spinner,custom. sectionsis optional; keys are validated and default tofalseif missing/invalid.- Valid section keys:
- Single mode:
barChart,convergence,frequencyTable,history - Two-event mode:
jointDistribution,twoWayTable
- Single mode:
- When
historyistrue(single mode only), the trial history appears as a standalone widget card instead of a modal. Two-event mode always uses the history button + modal. - Custom device settings:
- Single mode uses
deviceSettings; two-event mode usesdeviceASettings/deviceBSettings. outcomesmust contain 2-50 unique, non-empty strings (extras are truncated; duplicates ignored).probabilitiesis optional; if present it must matchoutcomeslength and contain non-negative numbers. Values are normalized to sum to 1; invalid inputs fall back to a uniform distribution.
- Single mode uses
client/app.jsis the main entrypoint and orchestrates state, rendering, and controls.client/src/probability-lab/enginemutates state slices with pure, DOM-free logic.client/src/probability-lab/uiis the only place that touches the DOM or canvases.server.jsserves static files in production.- Activity logging:
client/src/shell/activity-logger.jsPOSTs JSON events to/log.- In dev, Vite proxies
/logto the API server (seevite.config.js). server.jsappends JSONL events toactivity.log.
App shell:
- btn-help
- probability-lab
Experiment summary:
- pl-open-settings
- pl-setup-device, pl-setup-sample-space
- pl-spinner-options, pl-spinner-sectors
- pl-bias-summary, pl-relationship-summary
Settings modal:
- pl-settings-modal
- pl-settings-section-probabilities, pl-settings-section-event
- pl-single-config, pl-two-config
- pl-bias-options, pl-bias-options-a, pl-bias-options-b
- pl-relationship
Controls:
- pl-reset, pl-step, pl-step-size, pl-auto, pl-auto-speed-container
- pl-run-mode-toggle-manual, pl-run-mode-toggle-auto
- pl-run-mode-manual, pl-run-mode-auto
Event builder:
- pl-event-outcomes
Visualization:
- pl-device-view, pl-trials, pl-last
- pl-history (button, hidden when history section is enabled)
History (modal):
- pl-history-modal
- pl-history-summary, pl-history-empty
- pl-history-scroller, pl-history-viewport, pl-history-items
- pl-history-jump-top, pl-history-jump-latest
History (standalone widget):
- pl-history-card
- pl-history-card-summary, pl-history-card-empty
- pl-history-card-scroller, pl-history-card-viewport, pl-history-card-items
- pl-history-card-jump-top, pl-history-card-jump-latest
Single-event view:
- pl-single-view
- pl-bar-chart-section, pl-bar-chart
- pl-convergence-card, pl-line-chart
- pl-frequency-card, pl-frequency-table
Two-event view:
- pl-two-view
- pl-joint-distribution-card, pl-heatmap, pl-cell-summary
- pl-two-way-table-card, pl-twoway-table
- Coin: two outcomes (Heads, Tails)
- Die: six outcomes (1-6)
- Spinner: configurable sectors (2-12)
- Custom: outcomes configured in
config.json(2-50) with optional probabilities and icon/name
- Independent: A and B drawn separately
- Dependent: Probabilistic dependence where "high" outcomes of A make "high" outcomes of B more
likely
- For all devices (including custom), "low half" vs "high half" is based on outcome order.
- If you want dependence to feel meaningful for custom devices, order outcomes from low → high.
- Bar chart: relative frequency of each outcome
- Line chart: convergence of estimated P(E) over trials
- Heatmap: joint relative frequencies for two events
- Frequency table: theoretical probability, count, relative frequency, delta
- Two-way table: joint counts and probabilities for two events
- Tests live under
tests/and run with Vitest (npm test). - Test files are
tests/**/*.test.jsortests/**/*.spec.js.
- Design system assets live in
client/design-system/. - Primary references:
client/design-system/README.md,client/design-system/agents.md, andclient/design-system/llms.txt. - JS components available: modal, numeric-slider, dropdown, horizontal-cards.
- The app currently imports modal and numeric-slider in
client/app.js. client/design-systemis a git submodule; do not edit it in this repo.TODO: Document the owner/workflow for proposing design system changes.
- Use Design System components and tokens whenever possible.
- Keep DOM IDs and config schemas in sync with
client/app.jsandclient/src/shell/config.js. - Maintain nested AGENTS files; they override this root doc for their directories.
- Do not modify git submodules (e.g.
client/design-system).