dreamstack/examples/showcase.html

1202 lines
45 KiB
HTML
Raw Permalink Normal View History

<!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>