Roam Drafting
Explore pattern drafting as a graph with a quantum walk that biases toward the next best step for designers.
Quantum walkยท graph exploration
Section ยท Quantum
full primer โThe hook.
Pattern drafting is laid out as a graph; a quantum walker explores it and lights up the most promising next step for fashion designers to take.
Why this primitiveQuantum walk is the right primitive here because pattern drafting reduces to a graph exploration problem; the kernel returns a result you can drop straight into the UI.
Kernel
a discrete-time quantum walk on a small graph returning a probability distribution over nodes after t steps
Drives the UI as
an animated graph where node opacity reflects walk probability
Appendix A
The mega-prompt.
This prompt is engineered to ship in a single Lovable build. Real Quantinuum Guppy/Selene circuit runs in the Linux sandbox at build time and the results are baked in as JSON. read the build strategy โ
~14.1 KB290 lines1 msg ยท ~5 credits
Build "Roam Drafting": a one-page quantum-walk pattern-drafting explorer for fashion designers.
โ ๏ธ BUDGET: FREE Lovable (~5 credits). Ship in ONE message. No auth, no database, no Lovable Cloud.
QUANTUM (build-time only):
1. pip install guppylang selene-sim in sandbox.
2. Create quantum/kernel.py: @guppy function implementing discrete-time quantum walk on 16-node graph, 8 time-steps, returning per-node probability distributions. MUST be real .py file (Guppy reads via inspect.getsource).
3. Create quantum/run.py: import kernel, compile with Guppy, run on Selene emulator (โค8 qubits, 256 shots), write results to src/data/quantum-results.json as array of {input: step_index, output: {node_0: prob, node_1: prob, ...}} records.
4. Execute quantum/run.py once during build. Commit quantum-results.json. No Python at runtime.
FRONTEND (TanStack Start, single route /):
- Import quantum-results.json statically.
- Layout: Card (left) with Slider (0โ7 steps) + Badge showing active step; Card (center) with animated graph visualization (16 nodes, opacity = probability from JSON); Card (right) with Tabs ("Results" | "Guppy Source").
- "Results" tab: show per-node probabilities for active step in a Table or Badge group.
- "Guppy Source" tab: display full contents of quantum/kernel.py in a <pre> block so judges verify real Selene quantum walk.
- Design: dark background (#1a1a1a), accent color deep indigo (#4c1d95), font family Inter, smooth Slider onChange โ graph re-render.
- Micro-interaction: node opacity transition 200ms on step change.
BUILD ORDER:
1. Create quantum/kernel.py (discrete-time walk, 16 nodes, 8 steps).
2. Create quantum/run.py (Guppy compile + Selene run_shots, write JSON).
3. Execute quantum/run.py in sandbox; verify src/data/quantum-results.json exists.
4. Build React page: import JSON, Slider + Card + Tabs + graph visualization.
5. Add "Quantum trace" disclosure (Results tab + Guppy Source toggle).
6. Deploy.
--- QUANTINUUM APPENDIX (self-contained reference โ paste verbatim) ---
[1] INSTALL (Lovable Linux sandbox):
python -m pip install --no-cache-dir guppylang selene-sim
[2] IMPORTS (use exactly these โ no other quantum libs):
# quantum/kernel.py and quantum/run.py top
from guppylang import guppy
from guppylang.std.builtins import result
from guppylang.std.quantum import qubit, h, cx, rx, ry, rz, measure, discard, t as tgate, tdg
from guppylang.std.angles import angle, pi
from selene_sim import build, Quest
import math, json, sys, tempfile, importlib.util, uuid
from pathlib import Path
[3] HARD RULES (violating any breaks the build):
- @guppy reads source via inspect.getsource โ kernels MUST live in a real .py file on disk. No exec(), no REPL strings, no inline templates.
- Allowed gate set ONLY: h, rx, ry, rz, cx, tgate, tdg. There is NO native ccx/toffoli, cswap, cphase, or crz โ decompose using the snippets in [7].
- Qubit ownership: a qubit passed to a function is moved. You MUST measure() or discard() every qubit exactly once; never reuse after measure.
- Angle hygiene before baking a float into generated source:
theta = ((theta + math.pi) % (2.0 * math.pi)) - math.pi
and write it with repr: f"... {theta!r} ..." (str(float) can truncate).
[4] SELENE SHOT LOOP (canonical):
compiled = my_kernel.compile()
runner = build(compiled)
shots = []
for shot in runner.run_shots(Quest(), n_qubits=N, n_shots=S):
shots.append({str(lbl): int(v) for lbl, v in shot})
# N = MAX number of qubits simultaneously LIVE in the kernel.
# measure(q) releases the slot, so one ancilla reused across k windows still counts as 1.
[5] DRIVER PATTERN โ sweep a kernel over many inputs (closures do NOT work):
ROOT = Path(__file__).resolve().parent.parent
if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT))
def run_one(params: dict, shots: int = 256):
# Bake params as literals into a fresh .py file that imports your kernel helpers.
src = (
"from quantum.kernel import guppy, my_helper\n"
"@guppy\n"
"def program() -> None:\n"
f" my_helper({params['a']!r}, {params['b']!r})\n"
)
tmp = Path(tempfile.gettempdir()) / "qprogs"; tmp.mkdir(exist_ok=True)
name = f"prog_{uuid.uuid4().hex[:8]}"
path = tmp / f"{name}.py"; path.write_text(src)
spec = importlib.util.spec_from_file_location(name, path)
mod = importlib.util.module_from_spec(spec)
sys.modules[name] = mod # register BEFORE exec_module
spec.loader.exec_module(mod)
runner = build(mod.program.compile())
out = []
for shot in runner.run_shots(Quest(), n_qubits=5, n_shots=shots):
out.append({str(l): int(v) for l, v in shot})
return out
[6] PER-QUBIT INTEGER DECODE (host-side):
# kernel emits: for j in range(n): result(f"x{j}", measure(q[j]))
def decode(rec, n):
x = 0
for j in range(n): x |= (rec.get(f"x{j}", 0) & 1) << j
return x
[7] DECOMPOSITION LIBRARY (copy verbatim into quantum/kernel.py):
# ---- Toffoli (CCX) from H, CX, T, Tdg โ 6-T standard decomposition ----
@guppy
def toffoli(c1: qubit, c2: qubit, tgt: qubit) -> None:
h(tgt)
cx(c2, tgt); tdg(tgt)
cx(c1, tgt); tgate(tgt)
cx(c2, tgt); tdg(tgt)
cx(c1, tgt); tgate(c2); tgate(tgt)
h(tgt)
cx(c1, c2); tgate(c1); tdg(c2)
cx(c1, c2)
# ---- CSWAP (Fredkin) from CX + Toffoli ----
@guppy
def cswap(c: qubit, a: qubit, b: qubit) -> None:
cx(b, a)
toffoli(c, a, b)
cx(b, a)
# ---- Controlled phase exp(i*theta) on |11> from rz + cx ----
@guppy
def cphase(c: qubit, d: qubit, theta: float) -> None:
rz(d, angle(theta / 2.0))
cx(c, d)
rz(d, angle(-theta / 2.0))
cx(c, d)
# ---- Amplitude-encoded feature state (3 floats in [0,1] โ 2-qubit state) ----
@guppy
def prep_features(q0: qubit, q1: qubit, a: float, b: float, c: float) -> None:
ry(q0, angle(a))
ry(q1, angle(b))
cx(q0, q1)
rz(q1, angle(c))
# ---- SWAP test kernel; HOST inverts: F = clamp(2*P(anc=0) - 1, 0, 1) ----
@guppy
def swap_test(ai: float, bi: float, ci: float,
aj: float, bj: float, cj: float) -> None:
anc = qubit()
pi0 = qubit(); pi1 = qubit()
pj0 = qubit(); pj1 = qubit()
prep_features(pi0, pi1, ai, bi, ci)
prep_features(pj0, pj1, aj, bj, cj)
h(anc)
cswap(anc, pi0, pj0)
cswap(anc, pi1, pj1)
h(anc)
result("anc", measure(anc))
discard(pi0); discard(pi1); discard(pj0); discard(pj1)
# n_qubits = 5 for swap_test above.
[8] CLASSICAL CROSS-CHECK (NumPy reference โ commit alongside quantum result):
import numpy as np
I = np.eye(2); X = np.array([[0,1],[1,0]])
def RY(t): c,s = math.cos(t/2), math.sin(t/2); return np.array([[c,-s],[s,c]])
def RZ(t): return np.array([[np.exp(-1j*t/2),0],[0,np.exp(1j*t/2)]])
CX = np.array([[1,0,0,0],[0,1,0,0],[0,0,0,1],[0,0,1,0]])
def prep_psi(a,b,c):
s = np.kron(RY(a)@np.array([1,0]), RY(b)@np.array([1,0]))
s = CX @ s
s = np.kron(I, RZ(c)) @ s
return s
def classical_fidelity(p, q):
return float(abs(np.vdot(prep_psi(*p), prep_psi(*q)))**2)
# Commit BOTH quantum and classical values per record:
# {"input": [...], "quantum": 0.873, "classical": 0.881, "shots": 256}
[9] FRONTEND HANDOFF (TanStack Start):
# quantum/run.py last step:
Path("src/data/quantum-results.json").write_text(json.dumps({
"records": records, # list of {input, quantum, classical, ...}
"circuit": {"n_qubits": 5, "shots": 256},
"kernel_source": Path("quantum/kernel.py").read_text(), # show on /code tab
}, indent=2))
# In React: import data from "@/data/quantum-results.json" (resolveJsonModule:true).
# Render data.records; render data.kernel_source in a <pre> inside the Quantum trace tab.
[10] BUILD ORDER (do not deviate โ keeps you under 5 credits):
1. Write quantum/kernel.py with the helpers from [7] you actually need.
2. Write quantum/run.py: driver pattern from [5], Selene loop from [4], cross-check from [8], JSON write from [9].
3. Execute once: python quantum/run.py (commit src/data/quantum-results.json).
4. Build the React route: static JSON import, shadcn Card + Tabs + Slider + Badge wiring.
5. Deploy. No Python at runtime; every on-screen number traces to committed Selene output.
[11] OUTPUT CONTRACT โ selene_run v1 (write this exact shape to src/data/quantum-results.json):
{
"schemaVersion": 1,
"experiment": "<idea-slug>",
"title": "<idea title>",
"description": "<one plain-English sentence โ what a non-quantum dev sees>",
"kernel": { "snippet": "<first 40 lines of quantum/kernel.py>", "qubits": <int>, "shotsPerRow": <int> },
"verdict": { "text": "<one-sentence headline of the result>", "good": true },
"metrics": [ { "name": "<label>", "value": <number>, "unit": "<%|bits|Hz|...>", "good": true } ],
"series": [ { "id": "<id>", "kind": "histogram"|"bar"|"line", "title": "...",
"xLabel": "...", "yLabel": "...", "yKeys": ["count"],
"points": [ { "label": "<x>", "values": { "count": <num> } } ] } ]
}
Reason: one schema = one renderer = a polished demo without bespoke React per idea.
All metric / series VALUES must come from real Selene shot data committed in step 3 โ no mocks.
[12] RENDERER โ create src/components/SeleneRunView.tsx with EXACTLY this body (no deps beyond react + tailwind):
import * as React from "react";
type Point = { label: string; values: Record<string, number> };
type Series = { id: string; kind: "histogram"|"bar"|"line"; title: string;
xLabel?: string; yLabel?: string; yKeys: string[]; points: Point[] };
type Metric = { name: string; value: number; unit?: string; good?: boolean };
export type SeleneRun = {
schemaVersion: 1; experiment: string; title: string; description: string;
kernel: { snippet: string; qubits: number; shotsPerRow: number };
verdict: { text: string; good: boolean };
metrics: Metric[]; series: Series[]; notes?: string;
};
const fmt = (n: number) => Math.abs(n) >= 100 ? n.toFixed(0) : Math.abs(n) >= 1 ? n.toFixed(2) : n.toFixed(3);
function Bars({ s }: { s: Series }) {
const max = Math.max(1, ...s.points.flatMap(p => s.yKeys.map(k => p.values[k] ?? 0)));
return (
<div className="space-y-1">
{s.points.map((p, i) => (
<div key={i} className="flex items-center gap-2 text-xs">
<div className="w-20 truncate text-muted-foreground">{p.label}</div>
<div className="flex-1 h-3 bg-muted rounded-sm overflow-hidden">
<div className="h-full bg-primary" style={{ width: `${(100*(p.values[s.yKeys[0]]??0))/max}%` }} />
</div>
<div className="w-12 text-right tabular-nums">{fmt(p.values[s.yKeys[0]]??0)}</div>
</div>
))}
</div>
);
}
function Line({ s }: { s: Series }) {
const W=320, H=120, P=20;
const ys = s.points.map(p => p.values[s.yKeys[0]] ?? 0);
const min = Math.min(...ys), max = Math.max(...ys), span = max - min || 1;
const pts = ys.map((y, i) => {
const x = P + (i*(W-2*P))/Math.max(1, ys.length-1);
const yy = H - P - ((y - min)/span)*(H - 2*P);
return `${x},${yy}`;
}).join(" ");
return (
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-32">
<polyline fill="none" stroke="currentColor" strokeWidth="2" points={pts} className="text-primary" />
</svg>
);
}
export function SeleneRunView({ run }: { run: SeleneRun }) {
return (
<div className="space-y-6">
<header>
<div className="text-xs uppercase tracking-wider text-muted-foreground">{run.experiment}</div>
<h2 className="text-2xl font-semibold">{run.title}</h2>
<p className="text-sm text-muted-foreground">{run.description}</p>
<div className={`mt-2 inline-block px-3 py-1 rounded-full text-xs ${run.verdict.good?"bg-emerald-500/15 text-emerald-400":"bg-amber-500/15 text-amber-400"}`}>
{run.verdict.text}
</div>
</header>
<section className="grid grid-cols-2 md:grid-cols-4 gap-3">
{run.metrics.map((m, i) => (
<div key={i} className="rounded-lg border border-border p-3">
<div className="text-[10px] uppercase tracking-wider text-muted-foreground">{m.name}</div>
<div className="text-xl font-semibold tabular-nums">{fmt(m.value)}<span className="text-xs text-muted-foreground ml-1">{m.unit}</span></div>
</div>
))}
</section>
<section className="space-y-6">
{run.series.map(s => (
<div key={s.id} className="rounded-lg border border-border p-4">
<div className="flex items-baseline justify-between mb-3">
<div className="text-sm font-medium">{s.title}</div>
<div className="text-[10px] text-muted-foreground">{s.xLabel} / {s.yLabel}</div>
</div>
{s.kind === "line" ? <Line s={s} /> : <Bars s={s} />}
</div>
))}
</section>
<footer className="text-[11px] text-muted-foreground">
kernel: {run.kernel.qubits} qubits ยท {run.kernel.shotsPerRow} shots/row
</footer>
</div>
);
}
Then in the route: import data from "@/data/quantum-results.json"; <SeleneRunView run={data as any} />.
Quantum trace tab: <pre>{data.kernel.snippet}</pre>.
[HOOK] QUANTUM WALK โ coin + position register.
1 coin qubit c + n position qubits p[0..n-1]. Per step:
h(c)
# controlled increment of position register conditioned on c==1:
# for each bit j from n-1 down to 0, apply a multi-control X with controls (c, p[0..j-1])
# using the Toffoli ladder from [7].
Run ~n steps; measure p[]; bin shot frequencies into a 2**n-bin distribution.
selene_run mapping:
metrics: [ {"name":"peak node","value":peak_idx,"unit":""},
{"name":"steps","value":steps,"unit":""} ]
series: [ {"id":"node-prob","kind":"bar","title":"Probability per node",
"xLabel":"node","yLabel":"P","yKeys":["count"],
"points":[{"label":str(i),"values":{"count":p}} for i,p in enumerate(probs)]} ]Market sizing.
TAM
$2.0B
the fashion design software market (~$1.2B) within a $2.5T global fashion industry.
SAM
$480M
the 24% of that market actively buying pattern drafting-adjacent software.
SOM
$5M
a realistic 1% capture of the serviceable slice in years 1โ3 via the hackathon launch and creator-led distribution.
Indicative figures for hackathon pitches โ refine with your own research before raising.
Adjacent entries.
mood boards
Cascade Board
Explore mood boards as a graph with a quantum walk that biases toward the next best step for designers.
fabric sourcingFlux Sourcing
Explore fabric sourcing as a graph with a quantum walk that biases toward the next best step for designers.
pattern draftingMirror Drafting
Compare pattern drafting candidates by quantum fidelity so designers pick the closest match in one tap.
pattern draftingSilhouette Drafting
Reveal the topological shape (clusters, loops, voids) hiding inside pattern drafting so designers read structure at a glance.