dreamstack/examples/showcase.html
enzotar bbdeb6b82b feat: showcase — What DreamStack Does That Nothing Else Can
Interactive page comparing 5 unique DreamStack capabilities vs React/Svelte/Solid/Vue:
1. Reactivity as a type (Signal<T> in the type system)
2. Algebraic effects (swappable side-effect handlers)
3. Springs are signals (physics auto-propagates through reactive graph)
4. Compile-time dependency graph (static analysis, dead signal elimination)
5. Constraint-based layout (Cassowary solver, not CSS hacks)

Includes live spring physics demo, interactive constraint layout toggle,
side-by-side code comparisons, Elm-style error previews, and comparison table.
2026-02-25 00:34:46 -08:00

1202 lines
No EOL
45 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DreamStack — What No Other Framework Can Do</title>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap"
rel="stylesheet">
<style>
:root {
--bg: #050510;
--surface: #0c0c1d;
--surface-2: #12122a;
--border: #1e1e3a;
--text: #e8e8f0;
--text-dim: #6b6b8a;
--accent: #7c3aed;
--accent-2: #a855f7;
--green: #22c55e;
--red: #ef4444;
--blue: #3b82f6;
--yellow: #eab308;
--pink: #ec4899;
--orange: #f97316;
--cyan: #06b6d4;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: var(--bg);
color: var(--text);
font-family: 'Inter', -apple-system, system-ui, sans-serif;
overflow-x: hidden;
}
/* ─── Hero ───────────────────────────────────── */
.hero {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 40px 20px;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(ellipse 600px 400px at 30% 20%, rgba(124, 58, 237, 0.12) 0%, transparent 70%),
radial-gradient(ellipse 500px 350px at 70% 60%, rgba(168, 85, 247, 0.08) 0%, transparent 70%),
radial-gradient(ellipse 400px 300px at 50% 80%, rgba(59, 130, 246, 0.06) 0%, transparent 70%);
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 16px;
border-radius: 20px;
background: rgba(124, 58, 237, 0.15);
border: 1px solid rgba(124, 58, 237, 0.3);
font-size: 13px;
font-weight: 500;
color: var(--accent-2);
margin-bottom: 24px;
position: relative;
}
.hero h1 {
font-size: clamp(36px, 5vw, 64px);
font-weight: 800;
line-height: 1.1;
margin-bottom: 20px;
position: relative;
background: linear-gradient(135deg, #fff 0%, #c4b5fd 50%, #7c3aed 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.hero p {
font-size: 18px;
color: var(--text-dim);
max-width: 600px;
line-height: 1.6;
position: relative;
}
/* ─── Section ────────────────────────────────── */
.section {
padding: 80px 20px;
max-width: 1200px;
margin: 0 auto;
}
.section-header {
text-align: center;
margin-bottom: 60px;
}
.section-num {
display: inline-block;
font-size: 13px;
font-weight: 600;
color: var(--accent);
letter-spacing: 0.1em;
text-transform: uppercase;
margin-bottom: 12px;
}
.section h2 {
font-size: 36px;
font-weight: 700;
margin-bottom: 12px;
}
.section h2 em {
font-style: normal;
color: var(--accent-2);
}
.section .subtitle {
font-size: 16px;
color: var(--text-dim);
max-width: 600px;
margin: 0 auto;
line-height: 1.5;
}
/* ─── Comparison Card ────────────────────────── */
.comparison {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-top: 40px;
}
.code-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
overflow: hidden;
transition: transform 0.3s, box-shadow 0.3s;
}
.code-card:hover {
transform: translateY(-2px);
}
.code-card.dreamstack {
border-color: rgba(124, 58, 237, 0.4);
box-shadow: 0 0 40px rgba(124, 58, 237, 0.08);
}
.code-card.dreamstack:hover {
box-shadow: 0 8px 40px rgba(124, 58, 237, 0.15);
}
.code-card.others {
border-color: rgba(255, 255, 255, 0.06);
}
.code-card-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 20px;
border-bottom: 1px solid var(--border);
}
.code-card-header .label {
font-size: 13px;
font-weight: 600;
display: flex;
align-items: center;
gap: 6px;
}
.code-card-header .tag {
font-size: 10px;
padding: 2px 8px;
border-radius: 4px;
font-weight: 500;
}
.tag-unique {
background: rgba(124, 58, 237, 0.2);
color: var(--accent-2);
}
.tag-impossible {
background: rgba(239, 68, 68, 0.15);
color: var(--red);
}
.tag-lines {
background: rgba(255, 255, 255, 0.06);
color: var(--text-dim);
}
.tag-error {
background: rgba(239, 68, 68, 0.15);
color: var(--red);
}
.code-card pre {
padding: 20px;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
line-height: 1.7;
overflow-x: auto;
color: #c9d1d9;
}
/* Syntax highlighting */
.kw {
color: #c678dd;
}
.fn {
color: #61afef;
}
.str {
color: #98c379;
}
.num {
color: #d19a66;
}
.op {
color: #56b6c2;
}
.cm {
color: #5c6370;
font-style: italic;
}
.ty {
color: #e5c07b;
}
.sig {
color: #c678dd;
}
.eff {
color: #e06c75;
}
.err {
color: #ef4444;
text-decoration: wavy underline;
text-decoration-color: #ef4444;
}
.dim {
opacity: 0.4;
}
/* ─── Feature Grid ───────────────────────────── */
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-top: 40px;
}
.feature-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 14px;
padding: 28px;
transition: all 0.3s;
}
.feature-card:hover {
border-color: rgba(124, 58, 237, 0.3);
transform: translateY(-2px);
}
.feature-icon {
font-size: 28px;
margin-bottom: 12px;
}
.feature-card h3 {
font-size: 17px;
font-weight: 600;
margin-bottom: 8px;
}
.feature-card p {
font-size: 14px;
color: var(--text-dim);
line-height: 1.5;
}
.feature-card .frameworks {
display: flex;
gap: 6px;
margin-top: 12px;
flex-wrap: wrap;
}
.fw-badge {
font-size: 11px;
padding: 2px 8px;
border-radius: 4px;
font-weight: 500;
}
.fw-no {
background: rgba(239, 68, 68, 0.12);
color: rgba(239, 68, 68, 0.7);
}
.fw-partial {
background: rgba(234, 179, 8, 0.12);
color: rgba(234, 179, 8, 0.7);
}
.fw-yes {
background: rgba(34, 197, 94, 0.12);
color: rgba(34, 197, 94, 0.7);
}
/* ─── Live Demo Pane ─────────────────────────── */
.demo-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
border-radius: 16px;
overflow: hidden;
border: 1px solid var(--border);
margin-top: 40px;
}
.demo-code {
background: var(--surface);
padding: 24px;
border-right: 1px solid var(--border);
}
.demo-code pre {
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
line-height: 1.7;
}
.demo-result {
background: var(--surface-2);
padding: 24px;
display: flex;
flex-direction: column;
gap: 16px;
}
.demo-result-label {
font-size: 12px;
font-weight: 600;
color: var(--text-dim);
letter-spacing: 0.05em;
text-transform: uppercase;
}
/* ─── Type error display ─────────────────────── */
.error-display {
background: #1a0a0a;
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 10px;
padding: 16px 20px;
font-family: 'JetBrains Mono', monospace;
font-size: 12.5px;
line-height: 1.6;
margin-top: 16px;
}
.error-display .error-header {
color: var(--red);
font-weight: 600;
}
.error-display .error-body {
color: #d4a0a0;
}
.error-display .error-hint {
color: var(--cyan);
font-style: italic;
}
/* ─── Diagram ────────────────────────────────── */
.diagram-row {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
padding: 20px 0;
}
.diagram-node {
padding: 10px 18px;
border-radius: 10px;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
font-weight: 500;
}
.diagram-node.signal {
background: rgba(124, 58, 237, 0.15);
border: 1px solid var(--accent);
color: #c4b5fd;
}
.diagram-node.derived {
background: rgba(59, 130, 246, 0.15);
border: 1px solid var(--blue);
color: #93c5fd;
}
.diagram-node.effect {
background: rgba(249, 115, 22, 0.15);
border: 1px solid var(--orange);
color: #fdba74;
}
.diagram-node.spring {
background: rgba(236, 72, 153, 0.15);
border: 1px solid var(--pink);
color: #f9a8d4;
}
.diagram-node.view {
background: rgba(34, 197, 94, 0.15);
border: 1px solid var(--green);
color: #86efac;
}
.diagram-arrow {
color: var(--text-dim);
font-size: 18px;
}
/* ─── Table ──────────────────────────────────── */
.comparison-table {
width: 100%;
border-collapse: collapse;
margin-top: 40px;
font-size: 14px;
}
.comparison-table th {
padding: 14px 16px;
text-align: left;
font-weight: 600;
font-size: 13px;
color: var(--text-dim);
border-bottom: 1px solid var(--border);
}
.comparison-table td {
padding: 14px 16px;
border-bottom: 1px solid rgba(30, 30, 58, 0.5);
}
.comparison-table tr:hover td {
background: rgba(124, 58, 237, 0.03);
}
.comparison-table .feature-name {
font-weight: 500;
}
.dot-yes {
color: var(--green);
}
.dot-no {
color: var(--red);
}
.dot-partial {
color: var(--yellow);
}
/* ─── Separator ──────────────────────────────── */
.sep {
width: 60px;
height: 3px;
background: linear-gradient(90deg, var(--accent), transparent);
margin: 80px auto;
border-radius: 2px;
}
/* ─── Responsive ─────────────────────────────── */
@media (max-width: 768px) {
.comparison,
.demo-container {
grid-template-columns: 1fr;
}
.demo-code {
border-right: none;
border-bottom: 1px solid var(--border);
}
}
/* ─── Animations ─────────────────────────────── */
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-6px);
}
}
.float-1 {
animation: float 3s ease-in-out infinite;
}
.float-2 {
animation: float 3s ease-in-out infinite 0.5s;
}
.float-3 {
animation: float 3s ease-in-out infinite 1s;
}
.float-4 {
animation: float 3s ease-in-out infinite 1.5s;
}
@keyframes pulse-line {
0% {
opacity: 0.3;
}
50% {
opacity: 1;
}
100% {
opacity: 0.3;
}
}
.pulse {
animation: pulse-line 2s ease-in-out infinite;
}
/* Live demo area */
.live-spring-demo {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 32px;
position: relative;
overflow: hidden;
margin-top: 24px;
}
.spring-track {
width: 100%;
height: 80px;
background: var(--surface-2);
border-radius: 12px;
position: relative;
cursor: pointer;
margin: 16px 0;
}
.spring-ball {
width: 50px;
height: 50px;
border-radius: 50%;
background: linear-gradient(135deg, var(--accent), var(--pink));
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 0 30px rgba(124, 58, 237, 0.4);
cursor: grab;
}
.spring-ball:active {
cursor: grabbing;
}
.spring-info {
display: flex;
gap: 20px;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--text-dim);
}
.spring-info span {
color: var(--accent-2);
}
.layout-viz {
display: grid;
grid-template-columns: 200px 1fr;
gap: 2px;
height: 200px;
border-radius: 12px;
overflow: hidden;
margin: 16px 0;
transition: grid-template-columns 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.layout-panel {
display: flex;
align-items: center;
justify-content: center;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
font-weight: 500;
transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.layout-sidebar {
background: rgba(124, 58, 237, 0.2);
color: var(--accent-2);
}
.layout-main {
background: rgba(59, 130, 246, 0.15);
color: var(--blue);
}
</style>
</head>
<body>
<!-- ═══════════════════════════════════════════════════ -->
<!-- HERO -->
<!-- ═══════════════════════════════════════════════════ -->
<section class="hero">
<div class="hero-badge">✦ Not another framework</div>
<h1>What DreamStack Does<br>That Nothing Else Can</h1>
<p>Five capabilities that exist nowhere else — not in React, Svelte, Solid, Vue, or any other framework. Each
one is novel. Together, they're a paradigm shift.</p>
</section>
<!-- ═══════════════════════════════════════════════════ -->
<!-- #1: SIGNALS IN THE TYPE SYSTEM -->
<!-- ═══════════════════════════════════════════════════ -->
<section class="section">
<div class="section-header">
<div class="section-num">Differentiator 01</div>
<h2>Reactivity is a <em>type</em>, not a runtime trick</h2>
<p class="subtitle">In every other framework, signals are invisible to the type system. You can pass a
signal where a plain value is expected and it silently breaks. DreamStack catches this <strong>at
compile time</strong>.</p>
</div>
<div class="comparison">
<div class="code-card dreamstack">
<div class="code-card-header">
<span class="label">⚡ DreamStack</span>
<span class="tag tag-unique">UNIQUE</span>
</div>
<pre><span class="cm">// The compiler KNOWS these are reactive</span>
<span class="kw">let</span> count = <span class="num">0</span> <span class="cm">// → Signal&lt;Int&gt;</span>
<span class="kw">let</span> name = <span class="str">"Ada"</span> <span class="cm">// → Signal&lt;String&gt;</span>
<span class="kw">let</span> doubled = count * <span class="num">2</span> <span class="cm">// → Derived&lt;Int&gt;</span>
<span class="kw">let</span> hot = count > <span class="num">10</span> <span class="cm">// → Derived&lt;Bool&gt;</span>
<span class="cm">// ✅ Type-safe: compiler verifies deps</span>
<span class="cm">// ✅ Auto-tracks what to re-render</span>
<span class="cm">// ✅ Zero accidental subscriptions</span></pre>
</div>
<div class="code-card others">
<div class="code-card-header">
<span class="label">React / Solid / Svelte</span>
<span class="tag tag-impossible">IMPOSSIBLE</span>
</div>
<pre><span class="cm">// TypeScript can't tell these apart:</span>
<span class="kw">const</span> [count, setCount] = useState(<span class="num">0</span>)
<span class="cm">// count is... number? Signal? Who knows?</span>
<span class="cm">// This compiles but SILENTLY BREAKS:</span>
<span class="kw">function</span> <span class="fn">add</span>(a: <span class="ty">number</span>, b: <span class="ty">number</span>) {
<span class="kw">return</span> a + b
}
<span class="fn">add</span>(count, <span class="num">5</span>) <span class="cm">// ← loses reactivity!</span>
<span class="cm">// No framework catches this at compile time</span></pre>
</div>
</div>
<!-- Show an actual compile error -->
<div class="error-display">
<div class="error-header">── TYPE MISMATCH ─────────────────────────────────────────</div>
<div class="error-body">
7:12
add(count, 5)
I was expecting:
Int
but found:
<span style="color: var(--accent-2)">Signal&lt;Int&gt;</span>
<span class="error-hint">Hint: Use `count.value` to unwrap the signal, or make `add` accept
Signal&lt;Int&gt;
to preserve reactivity.</span>
</div>
</div>
</section>
<div class="sep"></div>
<!-- ═══════════════════════════════════════════════════ -->
<!-- #2: ALGEBRAIC EFFECTS -->
<!-- ═══════════════════════════════════════════════════ -->
<section class="section">
<div class="section-header">
<div class="section-num">Differentiator 02</div>
<h2>Effects you can <em>swap at test time</em></h2>
<p class="subtitle">React has useEffect (untyped, untestable). DreamStack has algebraic effects — declare
what side-effects a function <em>may</em> perform, and the compiler enforces that every effect is
handled. Swap handlers for testing without touching business logic.</p>
</div>
<div class="comparison">
<div class="code-card dreamstack">
<div class="code-card-header">
<span class="label">⚡ DreamStack</span>
<span class="tag tag-unique">UNIQUE</span>
</div>
<pre><span class="cm">// Declare what effects exist</span>
<span class="kw">effect</span> <span class="fn">Http.get</span>(url: <span class="ty">String</span>): <span class="ty">Response</span>
<span class="kw">effect</span> <span class="fn">Time.delay</span>(ms: <span class="ty">Int</span>): <span class="ty">()</span>
<span class="cm">// Use them — the TYPE tracks it</span>
<span class="kw">let</span> search = (q) <span class="op">-></span> {
<span class="kw">perform</span> Time.delay(<span class="num">250</span>)
<span class="kw">perform</span> Http.get(<span class="str">"/api?q="</span> ++ q)
}
<span class="cm">// search : (String) -> Response ! Http, Time</span>
<span class="cm">// In production:</span>
<span class="kw">handle</span> { Http.get(u) <span class="op">-></span> fetch(u) }
<span class="cm">// In tests — SAME code, DIFFERENT handler:</span>
<span class="kw">handle</span> { Http.get(u) <span class="op">-></span> mock_data }</pre>
</div>
<div class="code-card others">
<div class="code-card-header">
<span class="label">React / Vue / Svelte</span>
<span class="tag tag-impossible">IMPOSSIBLE</span>
</div>
<pre><span class="cm">// Effects are opaque and untraceable</span>
<span class="fn">useEffect</span>(() <span class="op">=></span> {
fetch(<span class="str">'/api'</span>) <span class="cm">// ← hidden side-effect</span>
.then(r <span class="op">=></span> r.json())
.then(setData)
}, [query])
<span class="cm">// Questions no framework can answer:</span>
<span class="cm">// • What effects does this component perform?</span>
<span class="cm">// • Are all effects cleaned up?</span>
<span class="cm">// • Can I swap fetch for a mock?</span>
<span class="cm">// • Will this work without network?</span>
<span class="cm">//</span>
<span class="cm">// Answer: 🤷 good luck</span></pre>
</div>
</div>
<div class="error-display" style="border-color: rgba(249, 115, 22, 0.4); background: #1a120a;">
<div class="error-header" style="color: var(--orange);">── UNHANDLED EFFECT
──────────────────────────────────────</div>
<div class="error-body">
The function `search` performs the `Http` effect, but no handler is installed.
<span class="error-hint">Hint: Wrap the call in `handle(() => search(q), { "Http": ... })`</span>
</div>
</div>
</section>
<div class="sep"></div>
<!-- ═══════════════════════════════════════════════════ -->
<!-- #3: SPRINGS ARE SIGNALS -->
<!-- ═══════════════════════════════════════════════════ -->
<section class="section">
<div class="section-header">
<div class="section-num">Differentiator 03</div>
<h2>Physics values that <em>auto-propagate</em></h2>
<p class="subtitle">In other frameworks, spring animations are separate from state. In DreamStack, a spring
IS a signal — set its target and every derived value, every view binding, every layout constraint
updates automatically through the reactive graph. Physics and reactivity are one system.</p>
</div>
<div class="comparison">
<div class="code-card dreamstack">
<div class="code-card-header">
<span class="label">⚡ DreamStack</span>
<span class="tag tag-unique">UNIQUE</span>
</div>
<pre><span class="cm">// A spring IS a signal — same API, same graph</span>
<span class="kw">let</span> sidebar_w = <span class="fn">spring</span>(
target: <span class="num">240</span>,
stiffness: <span class="num">170</span>,
damping: <span class="num">26</span>
) <span class="cm">// → Spring&lt;Float&gt; (is-a Signal&lt;Float&gt;)</span>
<span class="cm">// Derived values track spring physics!</span>
<span class="kw">let</span> main_w = <span class="num">1000</span> - sidebar_w
<span class="cm">// main_w smoothly animates as sidebar springs</span>
<span class="cm">// Layout constraints + springs = magic</span>
<span class="kw">view</span> main = <span class="kw">row</span> [
panel { width: sidebar_w } <span class="cm">// springs!</span>
panel { width: main_w } <span class="cm">// auto-follows!</span>
]
<span class="kw">on</span> toggle <span class="op">-></span> sidebar_w.target = <span class="num">64</span>
<span class="cm">// Everything animates. Zero manual work.</span></pre>
</div>
<div class="code-card others">
<div class="code-card-header">
<span class="label">Framer Motion / React Spring</span>
<span class="tag tag-impossible">IMPOSSIBLE</span>
</div>
<pre><span class="cm">// Animation is separate from state</span>
<span class="kw">const</span> [sidebar, api] = <span class="fn">useSpring</span>({
width: expanded ? <span class="num">240</span> : <span class="num">64</span>
})
<span class="cm">// Want main panel to follow? Manual math:</span>
<span class="kw">const</span> main = sidebar.width.<span class="fn">to</span>(
w <span class="op">=></span> <span class="num">1000</span> - w
) <span class="cm">// ← manual interpolation per value</span>
<span class="cm">// Want derived-of-derived? More manual work.</span>
<span class="cm">// Want 5 things to follow? 5× manual.</span>
<span class="cm">// Physics never feeds back into the</span>
<span class="cm">// reactive graph. Two separate worlds.</span>
<span class="cm">//</span>
<span class="cm">// Spring ≠ Signal. They can't talk.</span></pre>
</div>
</div>
<!-- Interactive spring demo -->
<div class="live-spring-demo">
<div style="font-size: 13px; font-weight: 600; margin-bottom: 8px;">Live: click anywhere on the track →
spring physics</div>
<div class="spring-track" id="springTrack">
<div class="spring-ball" id="springBall" style="left: 50%"></div>
</div>
<div class="spring-info">
<div>position: <span id="springPos">50.0</span>%</div>
<div>velocity: <span id="springVel">0.0</span></div>
<div>target: <span id="springTarget">50.0</span>%</div>
<div>stiffness: <span>170</span></div>
<div>damping: <span>26</span></div>
</div>
</div>
<!-- Interactive layout demo -->
<div class="live-spring-demo" style="margin-top: 16px">
<div style="font-size: 13px; font-weight: 600; margin-bottom: 8px;">Live: constraint-based layout — click to
toggle sidebar</div>
<div class="layout-viz" id="layoutViz">
<div class="layout-panel layout-sidebar" id="layoutSidebar">sidebar: <span id="sidebarW">200</span>px
</div>
<div class="layout-panel layout-main" id="layoutMain">main: <span id="mainW">auto</span></div>
</div>
<div class="spring-info">
<div>constraint: <span>sidebar + main = 100%</span></div>
<div>sidebar.min: <span>64px</span></div>
<div>solver: <span>Cassowary</span></div>
</div>
<button id="toggleLayout"
style="margin-top: 12px; padding: 8px 20px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); cursor: pointer; font-family: inherit; font-size: 13px;">Toggle
sidebar ⟷</button>
</div>
</section>
<div class="sep"></div>
<!-- ═══════════════════════════════════════════════════ -->
<!-- #4: COMPILE-TIME DEPENDENCY GRAPH -->
<!-- ═══════════════════════════════════════════════════ -->
<section class="section">
<div class="section-header">
<div class="section-num">Differentiator 04</div>
<h2>The compiler <em>sees the whole graph</em></h2>
<p class="subtitle">In React/Solid, dependencies are discovered at runtime. DreamStack's compiler statically
analyzes the entire signal dependency graph before a single line runs. Dead signals get eliminated.
Over-subscription is impossible.</p>
</div>
<div class="diagram-row">
<div class="diagram-node signal float-1">count: Signal&lt;Int&gt;</div>
<div class="diagram-arrow"></div>
<div class="diagram-node derived float-2">doubled: Derived&lt;Int&gt;</div>
<div class="diagram-arrow"></div>
<div class="diagram-node spring float-3">anim_x: Spring&lt;Float&gt;</div>
<div class="diagram-arrow"></div>
<div class="diagram-node view float-4">view main: View</div>
</div>
<div class="diagram-row" style="margin-top: -10px">
<div class="diagram-node signal float-2">query: Signal&lt;String&gt;</div>
<div class="diagram-arrow"></div>
<div class="diagram-node effect float-3">search: ! Http, Time</div>
<div class="diagram-arrow"></div>
<div class="diagram-node derived float-4">results: Derived&lt;[Item]&gt;</div>
</div>
<div class="comparison" style="margin-top: 40px">
<div class="code-card dreamstack">
<div class="code-card-header">
<span class="label">⚡ DreamStack Compiler Output</span>
<span class="tag tag-unique">STATIC ANALYSIS</span>
</div>
<pre><span class="cm">// The compiler produces this at BUILD TIME:</span>
<span class="ty">Signal Graph</span> {
<span class="sig">count</span>: Source(Int) → [doubled, is_hot, view]
<span class="sig">doubled</span>: Derived(Int) ← [count]
<span class="sig">is_hot</span>: Derived(Bool) ← [count]
<span class="cm">// Dead signal detection:</span>
<span class="eff">⚠ unused_var</span>: Source(String) — <span class="cm">DEAD, eliminated</span>
<span class="cm">// Optimal subscription plan:</span>
view.main subscribes to: [count, doubled, is_hot]
<span class="cm">// NOT to unused_var — zero wasted work</span>
}</pre>
</div>
<div class="code-card others">
<div class="code-card-header">
<span class="label">React / Solid / Vue</span>
<span class="tag tag-impossible">RUNTIME ONLY</span>
</div>
<pre><span class="cm">// Dependency discovery happens AT RUNTIME</span>
<span class="cm">// The compiler has NO IDEA what subscribes to what</span>
<span class="fn">useEffect</span>(() <span class="op">=></span> {
<span class="cm">// React: "I'll figure it out when it runs"</span>
<span class="cm">// Missing dep? Silent stale closure bug.</span>
<span class="cm">// Extra dep? Runs too often.</span>
setDoubled(count * <span class="num">2</span>)
}, [count]) <span class="cm">// ← YOU must list deps manually</span>
<span class="cm">// In Solid: auto-tracking is runtime-only.</span>
<span class="cm">// Unused signals still exist in memory.</span>
<span class="cm">// Over-subscription? No compiler to warn you.</span></pre>
</div>
</div>
</section>
<div class="sep"></div>
<!-- ═══════════════════════════════════════════════════ -->
<!-- #5: INTEGRATED CONSTRAINT LAYOUT -->
<!-- ═══════════════════════════════════════════════════ -->
<section class="section">
<div class="section-header">
<div class="section-num">Differentiator 05</div>
<h2>Layout is <em>constraints</em>, not CSS hacks</h2>
<p class="subtitle">CSS was designed for documents, not UIs. DreamStack uses a Cassowary constraint solver —
the same algorithm Apple uses for Auto Layout. Declare relationships between elements, and the solver
finds the solution. No <code>flex-grow: 1; min-width: 0; overflow: hidden</code> nightmares.</p>
</div>
<div class="comparison">
<div class="code-card dreamstack">
<div class="code-card-header">
<span class="label">⚡ DreamStack</span>
<span class="tag tag-unique">CONSTRAINT SOLVER</span>
</div>
<pre><span class="cm">// Declare relationships. Solver does the math.</span>
<span class="kw">constraint</span> sidebar.width == <span class="num">200</span> @ Strong
<span class="kw">constraint</span> sidebar.width >= <span class="num">64</span> @ Required
<span class="kw">constraint</span> main.x == sidebar.x + sidebar.width
<span class="kw">constraint</span> main.x + main.width == <span class="num">1000</span>
<span class="cm">// The solver guarantees:</span>
<span class="cm">// • sidebar = 200, main = 800 (normal)</span>
<span class="cm">// • sidebar = 64, main = 936 (collapsed)</span>
<span class="cm">// • NEVER sidebar = -1 or main = NaN</span>
<span class="cm">// Bonus: constraint + spring = animated layout</span>
<span class="kw">constraint</span> sidebar.width == sidebar_spring
<span class="cm">// Physics drives layout. Solver maintains truth.</span></pre>
</div>
<div class="code-card others">
<div class="code-card-header">
<span class="label">CSS / Flexbox / Grid</span>
<span class="tag tag-impossible">NO SOLVER</span>
</div>
<pre><span class="cm">/* Hope and pray this works: */</span>
<span class="kw">.sidebar</span> {
width: <span class="num">200</span>px;
min-width: <span class="num">64</span>px;
flex-shrink: <span class="num">0</span>;
transition: width <span class="num">0.3</span>s;
}
<span class="kw">.main</span> {
flex: <span class="num">1</span>;
min-width: <span class="num">0</span>; <span class="cm">/* ← the classic hack */</span>
overflow: hidden; <span class="cm">/* ← another hack */</span>
}
<span class="cm">/* What if sidebar + main > viewport? */</span>
<span class="cm">/* What if content pushes sidebar wider? */</span>
<span class="cm">/* What if animation causes flash of wrong layout? */</span>
<span class="cm">/* CSS: ¯\_(ツ)_/¯ */</span></pre>
</div>
</div>
</section>
<div class="sep"></div>
<!-- ═══════════════════════════════════════════════════ -->
<!-- SUMMARY TABLE -->
<!-- ═══════════════════════════════════════════════════ -->
<section class="section">
<div class="section-header">
<h2>The Full Picture</h2>
<p class="subtitle">Five capabilities. Zero competitors have all five. Most have zero.</p>
</div>
<table class="comparison-table">
<thead>
<tr>
<th>Capability</th>
<th style="text-align:center">DreamStack</th>
<th style="text-align:center">React</th>
<th style="text-align:center">Svelte 5</th>
<th style="text-align:center">Solid</th>
<th style="text-align:center">Vue</th>
</tr>
</thead>
<tbody>
<tr>
<td class="feature-name">Signals in the type system</td>
<td style="text-align:center"><span class="dot-yes"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
</tr>
<tr>
<td class="feature-name">Algebraic effects (testable side-effects)</td>
<td style="text-align:center"><span class="dot-yes"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
</tr>
<tr>
<td class="feature-name">Springs are signals (unified graph)</td>
<td style="text-align:center"><span class="dot-yes"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
</tr>
<tr>
<td class="feature-name">Compile-time dependency graph</td>
<td style="text-align:center"><span class="dot-yes"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-partial">~</span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
</tr>
<tr>
<td class="feature-name">Constraint-based layout (Cassowary)</td>
<td style="text-align:center"><span class="dot-yes"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
<td style="text-align:center"><span class="dot-no"></span></td>
</tr>
<tr style="border-top: 2px solid var(--border)">
<td class="feature-name" style="font-weight: 700">Score</td>
<td style="text-align:center; font-weight: 700; color: var(--green)">5/5</td>
<td style="text-align:center; font-weight: 700; color: var(--red)">0/5</td>
<td style="text-align:center; font-weight: 700; color: var(--yellow)">~0.5/5</td>
<td style="text-align:center; font-weight: 700; color: var(--red)">0/5</td>
<td style="text-align:center; font-weight: 700; color: var(--red)">0/5</td>
</tr>
</tbody>
</table>
</section>
<div style="height: 80px"></div>
<!-- ═══════════════════════════════════════════════════ -->
<!-- SCRIPTS -->
<!-- ═══════════════════════════════════════════════════ -->
<script>
// ─── Spring Physics Engine (live demo) ──────────────
class Spring {
constructor(target, stiffness = 170, damping = 26, mass = 1) {
this.target = target;
this.position = target;
this.velocity = 0;
this.stiffness = stiffness;
this.damping = damping;
this.mass = mass;
}
step(dt) {
const force = -this.stiffness * (this.position - this.target);
const dampingForce = -this.damping * this.velocity;
const acceleration = (force + dampingForce) / this.mass;
this.velocity += acceleration * dt;
this.position += this.velocity * dt;
}
isAtRest() {
return Math.abs(this.velocity) < 0.01 && Math.abs(this.position - this.target) < 0.1;
}
}
// Spring demo
const spring = new Spring(50);
const ball = document.getElementById('springBall');
const posEl = document.getElementById('springPos');
const velEl = document.getElementById('springVel');
const targetEl = document.getElementById('springTarget');
const track = document.getElementById('springTrack');
track.addEventListener('click', (e) => {
const rect = track.getBoundingClientRect();
const pct = ((e.clientX - rect.left) / rect.width) * 100;
spring.target = Math.max(3, Math.min(97, pct));
targetEl.textContent = spring.target.toFixed(1);
});
function animateSpring() {
requestAnimationFrame(animateSpring);
const substeps = 8;
const dt = 1 / 60 / substeps;
for (let i = 0; i < substeps; i++) {
spring.step(dt);
}
ball.style.left = spring.position + '%';
posEl.textContent = spring.position.toFixed(1);
velEl.textContent = spring.velocity.toFixed(1);
}
animateSpring();
// ─── Layout constraint demo ─────────────────────────
let sidebarExpanded = true;
const layoutViz = document.getElementById('layoutViz');
const sidebarWEl = document.getElementById('sidebarW');
const mainWEl = document.getElementById('mainW');
document.getElementById('toggleLayout').addEventListener('click', () => {
sidebarExpanded = !sidebarExpanded;
const sidebarW = sidebarExpanded ? 200 : 64;
layoutViz.style.gridTemplateColumns = `${sidebarW}px 1fr`;
sidebarWEl.textContent = sidebarW;
mainWEl.textContent = `${layoutViz.offsetWidth - sidebarW}`;
});
// Update main width on resize
const resizeObs = new ResizeObserver(() => {
const sidebarW = sidebarExpanded ? 200 : 64;
mainWEl.textContent = `${layoutViz.offsetWidth - sidebarW}`;
});
resizeObs.observe(layoutViz);
</script>
</body>
</html>