Build NN·slug·status
Ship Season 01 · Build NN

Title

One-line promise.

${escapeHtml(p.name || 'Rik Ventura')}
${escapeHtml(p.handle || '@rikventure')}
${escapeHtml(body.trim())}
${p.scheduled ? `
scheduled: ${escapeHtml(p.scheduled)}
` : ''} `; } function renderStoryboard(src) { const items = parseListKv(src); return `
${items.map(i => `
${escapeHtml(i.key)}
${escapeHtml(i.val)}
`).join('')}
`; } function renderFunnel(src) { const items = parseListKv(src).map(i => ({ num: i.key, label: i.val })); const max = Math.max(...items.map(i => parseFloat(i.num.replace(/[^\d.]/g,'')) || 0)); return `
${items.map(i => { const v = parseFloat(i.num.replace(/[^\d.]/g,'')) || 0; const pct = max ? Math.max(2, (v / max) * 100) : 100; return `
${escapeHtml(i.num)} ${escapeHtml(i.label)}
`; }).join('')}
`; } function renderSwatches(src) { const items = parseListKv(src); return `
${items.map(i => `
${escapeHtml(i.key)}
${escapeHtml(i.val)}
`).join('')}
`; } function renderSpecStrip(src) { const items = parseListKv(src); const html = items.map(i => `
${escapeHtml(i.key)} ${escapeHtml(i.val)}
`).join(''); document.getElementById('spec-strip').innerHTML = html; } function renderFeatures(src) { const blocks = src.split(/\n---\n/); return `
${blocks.map(b => { const f = parseKv(b); const tier = (f.tier || 'p0').toLowerCase(); const dl = ['trigger','behavior','result','acceptance'].filter(k=>f[k]).map(k=>`
${k}
${escapeHtml(f[k])}
`).join(''); return `
${tier.toUpperCase()} ${escapeHtml(f.title || 'Feature')}
${dl}
`; }).join('')}
`; } function renderNogoals(src) { const items = parseList(src); return `
${items.map(i => `${escapeHtml(i)}`).join('')}
`; } function renderCompare(src) { const sides = src.split(/\n---\n/); return `
${sides.map(s => { const lines = s.trim().split('\n'); const head = lines.shift() || ''; return `

${escapeHtml(head.replace(/^#+\s*/,''))}

${marked.parse(lines.join('\n'))}
`; }).join('')}
`; } // ---- Slugify and section split function slugify(s){return s.toLowerCase().trim().replace(/[`*_~]/g,'').replace(/[^\w\s-]/g,'').replace(/\s+/g,'-').replace(/-+/g,'-');} function splitSections(md) { const lines = md.split('\n'); const sections = []; let cur = { heading: null, id: null, body: [] }; let inFence = false; for (const line of lines) { if (/^```/.test(line)) inFence = !inFence; if (!inFence && /^##\s+/.test(line)) { if (cur.heading || cur.body.length) sections.push(cur); const txt = line.replace(/^##\s+/, '').trim(); cur = { heading: txt, id: slugify(txt.replace(/`P[01]`|`LOCKED`|`DONE`/g, '')), body: [line] }; } else cur.body.push(line); } if (cur.heading || cur.body.length) sections.push(cur); return sections; } function pillify(html) { return html .replace(/P0<\/code>/g, 'P0') .replace(/P1<\/code>/g, 'P1') .replace(/LOCKED<\/code>/g, 'LOCKED') .replace(/DONE<\/code>/g, 'DONE'); } // ---- Render pipeline const sections = splitSections(sourceMd); const main = $('#content'); const tocList = $('#toc'); // Strip the markdown H1 — the hero owns the title const preamble = sections.length && !sections[0].heading ? sections.shift() : null; if (preamble) { const noH1 = preamble.body.join('\n').replace(/^#\s.+$/m, '').trim(); if (noH1) { const wrap = document.createElement('div'); wrap.innerHTML = pillify(marked.parse(noH1)); main.appendChild(wrap); } } const distributionRegex = /distribution|launch.*plan|channel/i; let secNum = 0; for (const sec of sections) { secNum++; const sectionMd = sec.body.join('\n'); const html = pillify(marked.parse(sectionMd)); const wrap = document.createElement('section'); wrap.id = sec.id; wrap.innerHTML = html; const h2 = wrap.querySelector('h2'); if (h2) { h2.id = sec.id; // Numbered marker const num = document.createElement('span'); num.className = 'h2-num'; num.textContent = String(secNum).padStart(2, '0'); const txt = document.createElement('span'); txt.className = 'h2-text'; while (h2.firstChild) txt.appendChild(h2.firstChild); h2.append(num, txt); // Tier class for minimal mode + section coloring if (h2.querySelector('.pill.p1')) wrap.classList.add('tier-p1'); else wrap.classList.add('tier-p0'); // Hover copy-as-prompt const actions = document.createElement('div'); actions.className = 'section-actions'; const btn = document.createElement('button'); btn.className = 'btn'; btn.textContent = 'Copy section'; btn.addEventListener('click', () => { navigator.clipboard.writeText(sectionMd).then(() => toast('Copied: ' + sec.heading.replace(/`.*`/g, '').trim())); }); actions.appendChild(btn); h2.insertAdjacentElement('afterend', actions); } // Wrap distribution-shaped tables for nicer styling if (distributionRegex.test(sec.heading || '')) { wrap.querySelectorAll('table').forEach(t => { const w = document.createElement('div'); w.className = 'distribution-table'; t.parentNode.insertBefore(w, t); w.appendChild(t); }); } main.appendChild(wrap); // TOC entry const li = document.createElement('li'); if (wrap.classList.contains('tier-p1')) li.className = 'tier-p1'; const a = document.createElement('a'); a.href = '#' + sec.id; const cleanHeading = sec.heading.replace(/`P[01]`|`LOCKED`|`DONE`/g, '').trim(); a.innerHTML = `${String(secNum).padStart(2, '0')}${escapeHtml(cleanHeading)}`; li.appendChild(a); tocList.appendChild(li); } // ---- Render Mermaid (wait for ESM import) function renderMermaid() { if (!window.__mermaid) return; window.__mermaid.run({ querySelector: '.mermaid' }).catch(e => console.warn('mermaid', e)); } if (window.__mermaid) renderMermaid(); else { const t = setInterval(() => { if (window.__mermaid) { clearInterval(t); renderMermaid(); } }, 50); } // ---- Scroll-spy const tocLinks = $$('aside.toc a'); const headingEls = $$('main section[id]'); function onScroll() { let active = null; const offset = 120; for (const el of headingEls) { if (el.getBoundingClientRect().top - offset <= 0) active = el.id; } tocLinks.forEach(a => a.classList.toggle('active', a.getAttribute('href') === '#' + active)); } window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); // ---- Toast function toast(msg) { const t = $('#toast'); t.textContent = msg; t.classList.add('show'); clearTimeout(toast._t); toast._t = setTimeout(() => t.classList.remove('show'), 1600); } // ---- Theme function setTheme(t) { document.documentElement.setAttribute('data-theme', t); localStorage.setItem('prd-theme', t); if (window.__mermaid) { window.__mermaid.initialize({ startOnLoad: false, theme: t === 'light' ? 'default' : 'dark' }); $$('.mermaid').forEach(el => { el.removeAttribute('data-processed'); }); window.__mermaid.run({ querySelector: '.mermaid' }).catch(()=>{}); } } const savedTheme = localStorage.getItem('prd-theme'); if (savedTheme) setTheme(savedTheme); $('#toggle-theme').addEventListener('click', () => { setTheme(document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'); }); // ---- Minimal mode function setMinimal(on) { document.body.classList.toggle('minimal', on); $('#toggle-minimal').textContent = on ? 'All' : 'P0'; } if (new URLSearchParams(location.search).get('minimal') === '1') setMinimal(true); $('#toggle-minimal').addEventListener('click', () => { setMinimal(!document.body.classList.contains('minimal')); }); // ---- Copy CLAUDE.md block $('#copy-claudemd').addEventListener('click', () => { const target = sections.find(s => /CLAUDE\.md|agent\s*context/i.test(s.heading || '')); if (!target) { toast('No CLAUDE.md block found'); return; } const body = target.body.join('\n'); const fence = body.match(/```(?:markdown)?\n([\s\S]*?)\n```/); const text = fence ? fence[1] : body; navigator.clipboard.writeText(text).then(() => toast('CLAUDE.md block copied')); }); })();