Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

wcstack examples

Cross-package demo apps: each one composes two or more wcstack packages (or showcases a repo-level concern like SSR or framework interop). Focused single-package demos live in that package's own examples/ directory instead:

  • packages/fetch/examples/pagination (5-stack comparison), users-crud, infinite-scroll
  • packages/speech/examples/speech-echo, speak-highlight
  • packages/defined/examples/defined-loader
  • packages/midi/examples/midi-fader
  • packages/view-transition/examples/list-transitions
  • packages/state/examples/ — binding basics

Every demo is buildless and loads packages straight from the CDN (https://esm.run/@wcstack/<pkg>/auto one-liners; signals demos import the single @wcstack/signals/dom entry) — except the React/Vue variants of websocket-chat, which use Vite.

Script order: list the I/O-node packages before @wcstack/state. Module scripts execute in document order, so this guarantees every custom element is defined before state attaches its bindings — and the guarantee is worth more than tidiness:

  • A property / spread binding on a not-yet-defined element is deferred via customElements.whenDefined and re-applied with the latest value once the class arrives, so nothing is lost there.
  • A command-token emit is not replayed. Its subscription is deferred the same way, so if state is wired first and a slow (or failed) CDN fetch leaves an I/O element undefined, a click that fires $command.x.emit() inside that window reaches zero subscribers and is silently dropped.

Loading state last closes that window: nothing is wired to the UI until every element is defined. When you cannot control the order — a snippet pasted into a larger page, or tags arriving through @wcstack/autoloader — gate the control that emits with @wcstack/defined: bind <wcs-defined>'s pending to a disabled: and the button cannot be clicked before the subscriptions exist. Prefer it over awaiting customElements.whenDefined() inside the handler, which never rejects for a tag that is never registered and so parks the handler forever on a failed import. See state-tilt-maze/.

Demo list

Demo Combines Run URL
websocket-chat/ websocket × 5 stacks (vanilla / state / signals / React / Vue) see its README :3300–:3302, :3304–:3305
router-spa/ router + fetch + state (SPA catalog: URL ⇄ state bridge) node examples/router-spa/server.js :3000
router-i18n/ router + state (i18n: locale in the basename, dictionary as an ES module) node examples/router-i18n/server.js :3000
state-camera-record-upload/ camera + permission + upload + state any static server (secure context)
state-color-palette/ eyedropper + clipboard + storage + state any static server (EyeDropper is Chromium-only)
state-cross-tab-todo/ storage + broadcast + state node examples/state-cross-tab-todo/server.js (open 2 tabs) :3000
state-custom-states/ fetch + websocket + state (:state() showcase) node examples/state-custom-states/server.js (needs the websocket-chat shared install) :3303
state-devtools-playground/ devtools + state + timer (overlay inspector demo) any static server
state-intersect-scroll/ intersection + state ($streams switchMap restart + bounded retry, $scan feed accumulation) node examples/state-intersect-scroll/server.js :3000
state-notification-chat/ notification + permission + state any static server
state-permission-banner/ geolocation + permission + state any static server
state-pomodoro/ timer + wakelock + notification + state any static server (secure context)
state-search/ fetch + debounce + state node examples/state-search/server.js :3000
state-sse-dashboard/ sse + state ($streams) + network — one feed, two idioms node examples/state-sse-dashboard/server.js :3000
state-testing-todo/ testing + state (a todo page and its headless vitest suite) cd examples/state-testing-todo && npm install && npm test
state-tilt-maze/ tilt + accelerometer + raf + wakelock + defined + state (sensor game) any static server (secure context)
signals-live-search/ signals + fetch node examples/signals-live-search/server.js :3000
signals-tilt-maze/ signals × the same 4 sensor nodes as state-tilt-maze (core swap comparison) any static server (secure context)
ssr/ @wcstack/server (SSR + hydration) cd examples/ssr && npm install && node server.js :3001
synth-playground/ 🎹 audio + midi + state (a modular synth written as markup) any static server

Demos marked "any static server" have no backend at all — any way of serving the directory over http://localhost works, e.g.:

npx serve examples/state-permission-banner

Shared server core

shared/server.js is the static-file + JSON API core the demos above delegate to — each demo's server.js stays a thin file declaring only its own routes. When copying a single demo out of this repo, copy examples/shared/ alongside it. (websocket-chat/ is the exception: it ships its own self-contained server under websocket-chat/shared/ because it needs the ws dependency, so that scenario is portable as one directory.)

Most demo servers default to port 3000 (override with PORT=…), so run them one at a time — or use the e2e static server (cd e2e && npm run serve), which serves the whole repo with mocked APIs at http://127.0.0.1:4173.