mirror of
https://github.com/jparkerweb/plan2code.git
synced 2026-09-17 16:22:23 -07:00
452 lines
21 KiB
HTML
452 lines
21 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Plan2Code — Spec-Driven Workflow for AI Coding Agents</title>
|
|
<meta name="description" content="Send the plan — the build follows. You approve a plan, it becomes phase documents in your repo, and the agent builds to those documents one phase at a time.">
|
|
<link rel="icon" href="favicon.ico" sizes="32x32">
|
|
<link rel="icon" type="image/png" sizes="32x32" href="favicon.png">
|
|
<link rel="icon" href="favicon.svg" type="image/svg+xml">
|
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Big+Shoulders+Display:wght@500;700;800&family=Karla:wght@300;400;500;600;700&family=Caveat:wght@500&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root{
|
|
--air:#E4ECF6; --air-2:#D3DEEE; --paper:#FBFAF6;
|
|
--ink:#16233D; --ink-soft:#5E6E8A;
|
|
--red:#D33A38; --blue:#2455A4; --kraft:#E5D8BE;
|
|
}
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
html{scroll-behavior:smooth}
|
|
[id]{scroll-margin-top:90px}
|
|
body{background:var(--air);color:var(--ink);font:400 16.5px/1.65 'Karla',system-ui,sans-serif;-webkit-font-smoothing:antialiased}
|
|
.bs{font-family:'Big Shoulders Display',sans-serif;font-weight:800;letter-spacing:.005em}
|
|
.hand{font-family:'Caveat',cursive}
|
|
.wrap{max-width:1140px;margin:0 auto;padding:0 34px}
|
|
a{color:inherit}
|
|
:focus-visible{outline:2px solid var(--red);outline-offset:3px}
|
|
|
|
/* ── SIGNATURE: airmail chevron border framing the page on all four sides ── */
|
|
:root{--fr:11px}
|
|
.frame-t,.frame-b,.frame-l,.frame-r{
|
|
position:fixed;z-index:60;pointer-events:none;
|
|
background:repeating-linear-gradient(-45deg,
|
|
var(--red) 0 14px, var(--paper) 14px 28px,
|
|
var(--blue) 28px 42px, var(--paper) 42px 56px);
|
|
}
|
|
.frame-t,.frame-b{left:0;right:0;height:var(--fr)}
|
|
.frame-t{top:0}
|
|
.frame-b{bottom:0}
|
|
.frame-l,.frame-r{top:0;bottom:0;width:var(--fr)}
|
|
.frame-l{left:0}
|
|
.frame-r{right:0}
|
|
body{padding:var(--fr)}
|
|
|
|
/* ── header (sticky, sits just under the top frame) ── */
|
|
.top{
|
|
background:var(--paper);border-bottom:2px solid var(--ink);
|
|
position:sticky;top:var(--fr);z-index:40;
|
|
}
|
|
.top .wrap{display:flex;align-items:center;gap:16px;padding-top:13px;padding-bottom:12px}
|
|
.brand{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:26px;letter-spacing:.01em;text-transform:uppercase}
|
|
.brand i{font-style:normal;color:var(--red)}
|
|
.avion{
|
|
margin-left:auto;border:1.5px solid var(--blue);color:var(--blue);
|
|
font-size:10px;letter-spacing:.22em;text-transform:uppercase;font-weight:700;padding:5px 11px;
|
|
}
|
|
|
|
/* ── hero: the envelope ── */
|
|
.hero{padding:56px 0 70px}
|
|
.env{
|
|
background:var(--paper);border:2px solid var(--ink);position:relative;
|
|
box-shadow:10px 12px 0 rgba(22,35,61,.14);padding:40px 42px 44px;
|
|
}
|
|
/* cancellation waves */
|
|
.cancel{position:absolute;right:34px;top:34px;width:210px;height:110px;pointer-events:none}
|
|
.cancel .ring{fill:none;stroke:var(--red);stroke-width:2.2}
|
|
.cancel .wv{fill:none;stroke:var(--red);stroke-width:2.2;opacity:.85}
|
|
.cancel text{font-family:'Karla',sans-serif;font-weight:700;fill:var(--red);letter-spacing:.06em}
|
|
/* stamp */
|
|
.pstamp{
|
|
position:absolute;right:250px;top:34px;width:86px;height:104px;background:var(--air-2);
|
|
border:2px solid var(--ink);padding:8px;text-align:center;
|
|
}
|
|
.pstamp .in{border:1px solid rgba(22,35,61,.35);height:100%;display:flex;flex-direction:column;justify-content:center;gap:2px}
|
|
.pstamp b{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:26px;line-height:1;color:var(--blue)}
|
|
.pstamp span{font-size:8px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft);font-weight:700}
|
|
@media(max-width:900px){.cancel,.pstamp{display:none}}
|
|
|
|
.kick{font-size:10.5px;letter-spacing:.24em;text-transform:uppercase;color:var(--blue);font-weight:700}
|
|
h1{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:clamp(3rem,9vw,7rem);line-height:.86;text-transform:uppercase;margin-top:14px;max-width:13ch}
|
|
h1 em{font-style:normal;color:var(--red)}
|
|
.addr{
|
|
margin-top:32px;padding-top:26px;border-top:1.5px dashed rgba(22,35,61,.3);
|
|
display:grid;grid-template-columns:1fr 1fr;gap:36px;align-items:end;
|
|
}
|
|
.addr .to{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-soft);font-weight:700}
|
|
.addr p{margin-top:10px;color:var(--ink-soft);max-width:44ch}
|
|
.acts{display:flex;flex-wrap:wrap;gap:12px}
|
|
.btn{
|
|
display:inline-block;text-decoration:none;background:var(--ink);color:var(--paper);
|
|
font-family:'Big Shoulders Display',sans-serif;font-weight:700;font-size:19px;letter-spacing:.1em;
|
|
text-transform:uppercase;padding:12px 28px;transition:background .18s,transform .18s;
|
|
}
|
|
.btn:hover{background:var(--red);transform:translateY(-2px)}
|
|
.btn.-o{background:transparent;border:2px solid var(--ink);color:var(--ink);padding:10px 26px}
|
|
.btn.-o:hover{background:var(--ink);color:var(--paper)}
|
|
|
|
/* ── postage meter strip ── */
|
|
.meter{background:var(--ink);color:var(--paper)}
|
|
.meter .wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:0}
|
|
.meter div{padding:24px 18px;border-left:1px dashed rgba(251,250,246,.28)}
|
|
.meter div:first-child{border-left:none}
|
|
.meter b{display:block;font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:2.4rem;line-height:1;color:#8FB6E8}
|
|
.meter span{display:block;margin-top:3px;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;opacity:.66;font-weight:700}
|
|
|
|
/* ── dispatch (steps as airmail envelopes) ── */
|
|
.dispatch{padding:80px 0 40px}
|
|
.sect{display:flex;align-items:flex-end;gap:16px;border-bottom:2px solid var(--ink);padding-bottom:10px}
|
|
.sect h2{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:clamp(2rem,5vw,3.4rem);text-transform:uppercase;line-height:.95}
|
|
.sect span{margin-left:auto;font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-soft);font-weight:700;padding-bottom:5px}
|
|
|
|
.letters{display:grid;grid-template-columns:repeat(auto-fit,minmax(400px,1fr));gap:22px;margin-top:30px}
|
|
.ltr{
|
|
background:var(--paper);border:2px solid var(--ink);position:relative;
|
|
padding:26px 26px 28px 40px;display:flex;flex-direction:column;
|
|
box-shadow:6px 7px 0 rgba(22,35,61,.12);transition:transform .2s,box-shadow .2s;
|
|
}
|
|
.ltr:hover{transform:translate(-3px,-3px);box-shadow:9px 10px 0 rgba(22,35,61,.16)}
|
|
/* chevron spine */
|
|
.ltr::before{
|
|
content:'';position:absolute;left:0;top:0;bottom:0;width:14px;
|
|
background:repeating-linear-gradient(-45deg,var(--red) 0 10px,var(--paper) 10px 20px,var(--blue) 20px 30px,var(--paper) 30px 40px);
|
|
border-right:1px solid var(--ink);
|
|
}
|
|
.ltr .mark{
|
|
position:absolute;right:20px;top:18px;width:56px;height:56px;border:2px solid var(--red);border-radius:50%;
|
|
display:grid;place-items:center;text-align:center;transform:rotate(-11deg);
|
|
font-size:8.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--red);font-weight:700;line-height:1.25;
|
|
}
|
|
.ltr h3{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:1.9rem;text-transform:uppercase;line-height:1;padding-right:70px}
|
|
.ltr .flag{
|
|
display:inline-block;margin-left:9px;vertical-align:5px;font-family:'Karla',sans-serif;font-weight:700;
|
|
font-size:9px;letter-spacing:.11em;text-transform:uppercase;background:var(--blue);color:#fff;padding:3px 8px;
|
|
}
|
|
.ltr .flag.-r{background:var(--red)}
|
|
.ltr code{display:block;font-family:ui-monospace,Menlo,monospace;font-size:11.5px;color:var(--blue);margin-top:7px;font-weight:600}
|
|
.ltr p{margin-top:12px;color:var(--ink-soft);font-size:.94rem}
|
|
.ltr .pen{font-family:'Caveat',cursive;font-size:1.2rem;color:var(--red);margin-top:10px;transform:rotate(-.8deg)}
|
|
.ltr ul{list-style:none;margin-top:auto;padding-top:16px}
|
|
.ltr li{font-size:.85rem;padding:6px 0 6px 18px;position:relative;border-top:1px dotted rgba(22,35,61,.24)}
|
|
.ltr li::before{content:'✈';position:absolute;left:0;color:var(--blue);font-size:9px;top:9px}
|
|
|
|
/* ── two routes ── */
|
|
.routes{background:var(--paper);border-top:2px solid var(--ink);border-bottom:2px solid var(--ink);padding:76px 0;margin-top:56px}
|
|
.rc{display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:28px}
|
|
.rc div{border:2px solid var(--ink);padding:26px 24px}
|
|
.rc .-a{background:rgba(211,58,56,.06)}
|
|
.rc .-b{background:rgba(36,85,164,.06)}
|
|
.rc h4{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:1.5rem;text-transform:uppercase}
|
|
.rc ul{list-style:none;margin-top:14px}
|
|
.rc li{padding:9px 0 9px 24px;position:relative;font-size:.95rem;border-top:1px solid rgba(22,35,61,.14);color:var(--ink-soft)}
|
|
.rc li:first-child{border-top:none}
|
|
.rc .-a li::before{content:'✕';position:absolute;left:0;color:var(--red);font-weight:700}
|
|
.rc .-b li::before{content:'✓';position:absolute;left:0;color:var(--blue);font-weight:700}
|
|
|
|
/* ── regulations ── */
|
|
.regs{padding:78px 0}
|
|
.rg{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:0;margin-top:26px;border-top:2px solid var(--ink);border-left:2px solid var(--ink)}
|
|
.rg div{padding:22px 20px;border-right:2px solid var(--ink);border-bottom:2px solid var(--ink);background:var(--paper)}
|
|
.rg b{font-size:10px;letter-spacing:.15em;text-transform:uppercase;color:var(--red);font-weight:700}
|
|
.rg p{margin-top:9px;font-size:.94rem;color:var(--ink-soft)}
|
|
.rg p strong{color:var(--ink);font-weight:700}
|
|
|
|
/* ── install ── */
|
|
.install{padding:0 0 82px}
|
|
.termwrap{position:relative;margin-top:20px}
|
|
.term{background:var(--ink);color:#D6E2F2;padding:24px 76px 24px 24px;
|
|
font-family:ui-monospace,Menlo,monospace;font-size:12.5px;line-height:2.05;overflow-x:auto}
|
|
.term .c{color:#7488A6}.term .k{color:#F0B06A}.term .p{color:#8FB6E8}
|
|
.copy{
|
|
position:absolute;top:12px;right:12px;display:grid;place-items:center;gap:0;
|
|
width:40px;height:40px;background:transparent;border:1.5px solid rgba(214,226,242,.35);
|
|
color:#8FB6E8;cursor:pointer;transition:background .18s,color .18s,border-color .18s;
|
|
}
|
|
.copy:hover{background:#8FB6E8;color:var(--ink);border-color:#8FB6E8}
|
|
.copy svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
|
|
.copy .tick{display:none}
|
|
.copy.-done{border-color:#8FB6E8;color:#8FB6E8;background:transparent}
|
|
.copy.-done .clip{display:none}
|
|
.copy.-done .tick{display:block}
|
|
.copy-flash{
|
|
position:absolute;top:20px;right:62px;font-size:9.5px;letter-spacing:.16em;
|
|
text-transform:uppercase;font-weight:700;color:#8FB6E8;opacity:0;transition:opacity .18s;pointer-events:none;
|
|
}
|
|
.copy-flash.-on{opacity:1}
|
|
|
|
/* ── close ── */
|
|
.close{background:var(--ink);color:var(--paper);text-align:center;padding:92px 0}
|
|
.close h2{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:clamp(2.4rem,7vw,5.2rem);text-transform:uppercase;line-height:.9}
|
|
.close h2 em{font-style:normal;color:#8FB6E8}
|
|
.close .hand{display:block;margin-top:14px;font-size:1.5rem;color:#8FB6E8}
|
|
.close .btn{margin-top:24px;background:var(--red)}
|
|
.close .btn:hover{background:var(--paper);color:var(--ink)}
|
|
footer{background:var(--ink);color:rgba(251,250,246,.5);padding:0 0 28px;font-size:10px;letter-spacing:.15em;text-transform:uppercase;font-weight:700}
|
|
footer .wrap{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;border-top:1px dashed rgba(251,250,246,.24);padding-top:20px}
|
|
|
|
@media(max-width:700px){:root{--fr:8px}}
|
|
@media(max-width:820px){
|
|
.wrap{padding:0 20px}
|
|
.env{padding:26px 22px 28px}
|
|
.addr{grid-template-columns:1fr;gap:22px}
|
|
.rc{grid-template-columns:1fr}
|
|
.letters{grid-template-columns:1fr}
|
|
}
|
|
@media(prefers-reduced-motion:reduce){*{transition:none!important}html{scroll-behavior:auto}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="frame-t" aria-hidden="true"></div>
|
|
<div class="frame-b" aria-hidden="true"></div>
|
|
<div class="frame-l" aria-hidden="true"></div>
|
|
<div class="frame-r" aria-hidden="true"></div>
|
|
|
|
<header class="top">
|
|
<div class="wrap">
|
|
<span class="brand">PLAN<i>2</i>CODE</span>
|
|
<span class="avion">Par Avion · Via Air Mail</span>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="hero">
|
|
<div class="wrap">
|
|
<div class="env">
|
|
<div class="pstamp"><div class="in"><b>2.0</b><span>Plan2Code</span><span>Postage</span></div></div>
|
|
<svg class="cancel" viewBox="0 0 210 110" aria-hidden="true">
|
|
<circle class="ring" cx="52" cy="55" r="42"/>
|
|
<text x="52" y="46" text-anchor="middle" font-size="10">SHIPPED</text>
|
|
<text x="52" y="62" text-anchor="middle" font-size="13" font-weight="700">2026</text>
|
|
<text x="52" y="76" text-anchor="middle" font-size="8">NO REWORK</text>
|
|
<path class="wv" d="M98,36 C118,28 138,44 158,36 C178,28 194,40 208,34"/>
|
|
<path class="wv" d="M98,50 C118,42 138,58 158,50 C178,42 194,54 208,48"/>
|
|
<path class="wv" d="M98,64 C118,56 138,72 158,64 C178,56 194,68 208,62"/>
|
|
<path class="wv" d="M98,78 C118,70 138,86 158,78 C178,70 194,82 208,76"/>
|
|
</svg>
|
|
|
|
<p class="kick">Spec-driven workflow for AI coding agents</p>
|
|
<h1>Send the plan.<br>The build <em>follows</em>.</h1>
|
|
|
|
<div class="addr">
|
|
<div>
|
|
<p class="to">Addressed to</p>
|
|
<p>Anyone who has watched an AI agent confidently build the wrong thing. You approve a plan, it becomes phase documents in your repo, and the agent works to those documents one phase at a time.</p>
|
|
</div>
|
|
<div class="acts">
|
|
<a class="btn" href="#installation">Install Plan2Code</a>
|
|
<a class="btn -o" href="#dispatch">Read the letters</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="meter">
|
|
<div class="wrap">
|
|
<div><b>90%</b><span>Confidence gate</span></div>
|
|
<div><b>11</b><span>Review dimensions</span></div>
|
|
<div><b>1</b><span>Chat per phase</span></div>
|
|
<div><b>0</b><span>Context pollution</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<section class="dispatch wrap" id="dispatch">
|
|
<div class="sect"><h2>Six written letters</h2><span>Two optional</span></div>
|
|
|
|
<div class="letters">
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Opt<br>00</span>
|
|
<h3>Pathfinder<span class="flag">New in 2.0</span></h3>
|
|
<code>/plan2code-0-pathfinder</code>
|
|
<p>For an idea that arrives too foggy to plan. It charts the idea as a map of decision questions and clears exactly one per session until nothing is left to decide.</p>
|
|
<p class="pen">it never answers its own questions — that's the point</p>
|
|
<ul>
|
|
<li>One decision per file, one file per session</li>
|
|
<li>Research questions fan out to parallel agents</li>
|
|
<li>Clears at ≥18/25 on four confidence dimensions</li>
|
|
<li>Hands a hot plan draft to Step 1</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Req<br>01</span>
|
|
<h3>Plan</h3>
|
|
<code>/plan2code-1-plan</code>
|
|
<p>A real back-and-forth about what gets built. Requirements pulled apart, your codebase actually read, the stack confirmed rather than assumed.</p>
|
|
<ul>
|
|
<li>Functional and non-functional requirements</li>
|
|
<li>Integration points read from real source</li>
|
|
<li>Tech stack confirmed by explicit approval</li>
|
|
<li>Will not finalize below 90% confidence</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Req<br>02</span>
|
|
<h3>Document</h3>
|
|
<code>/plan2code-2-document</code>
|
|
<p>The plan stops being a conversation and becomes files — an overview plus one self-contained phase document per phase, cut into one-story-point tasks.</p>
|
|
<ul>
|
|
<li>overview.md and Phase 1…N.md land in your repo</li>
|
|
<li>One-point tasks with real checkboxes</li>
|
|
<li>Parallel groups marked for concurrent agents</li>
|
|
<li>Each phase readable with no prior context</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Req<br>03</span>
|
|
<h3>Implement</h3>
|
|
<code>/plan2code-3-implement</code>
|
|
<p>Build to the drawing, one phase per conversation. Planning context bleeding into implementation is where most agent drift starts.</p>
|
|
<p class="pen">reply “approved” — nothing advances on a guess</p>
|
|
<ul>
|
|
<li>Fresh conversation for every phase</li>
|
|
<li>Specs followed exactly as documented</li>
|
|
<li>Self-review against the spec before close</li>
|
|
<li>[/] claims prevent parallel-agent collisions</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Opt<br>✳</span>
|
|
<h3>Review<span class="flag -r">Second opinion</span></h3>
|
|
<code>/plan2code-review</code>
|
|
<p>An independent senior engineer with fresh eyes and no attachment to the code that just shipped. It reads every changed file completely and reports only what it can prove — file, line, and a concrete fix.</p>
|
|
<ul>
|
|
<li>Scope adapts: files, branch diff, or subsystem</li>
|
|
<li>All 11 dimensions reported, clean ones justified</li>
|
|
<li>Ranked Critical / Warning / Suggestion</li>
|
|
<li>Read-only until you reply H, A, or S 1,3,5</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Req<br>04</span>
|
|
<h3>Finalize</h3>
|
|
<code>/plan2code-4-finalize</code>
|
|
<p>Close it out. Every task audited against the spec it came from, a summary of what was built, docs checked for drift, and the folder filed away.</p>
|
|
<ul>
|
|
<li>Audit for tasks quietly left open</li>
|
|
<li>Summary of what was built and changed</li>
|
|
<li>README and other docs reconciled</li>
|
|
<li>Specs archived to specs--completed/</li>
|
|
</ul>
|
|
</article>
|
|
|
|
</div>
|
|
</section>
|
|
|
|
<section class="routes">
|
|
<div class="wrap">
|
|
<div class="sect"><h2>Two routes</h2><span>Same destination</span></div>
|
|
<div class="rc">
|
|
<div class="-a">
|
|
<h4>Sent without an address</h4>
|
|
<ul>
|
|
<li>Coding starts, requirements arrive later</li>
|
|
<li>Design problems surface mid-build</li>
|
|
<li>Constant backtracking and rework</li>
|
|
<li>Context bloated with abandoned attempts</li>
|
|
<li>No way to prove requirements were met</li>
|
|
<li>Tokens burned on trial and error</li>
|
|
</ul>
|
|
</div>
|
|
<div class="-b">
|
|
<h4>Sent with a plan attached</h4>
|
|
<ul>
|
|
<li>The plan is approved before any code</li>
|
|
<li>Problems caught while they are still cheap</li>
|
|
<li>Implementation follows the drawing</li>
|
|
<li>Clean context, one phase at a time</li>
|
|
<li>Checkboxes prove what is done</li>
|
|
<li>Tokens spent building the agreed thing</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="regs wrap">
|
|
<div class="sect"><h2>Postal regulations</h2><span>Four · non-negotiable</span></div>
|
|
<div class="rg">
|
|
<div><b>Reg 01</b><p>A <strong>fresh conversation</strong> for each step, and each implementation phase.</p></div>
|
|
<div><b>Reg 02</b><p>No code until the plan hits <strong>90% confidence</strong>. The gate does not negotiate.</p></div>
|
|
<div><b>Reg 03</b><p><strong>Checkboxes are the state</strong>, not the chat. Any session resumes cold.</p></div>
|
|
<div><b>Reg 04</b><p>Reply <strong>approved</strong> to close a phase. Nothing advances on a guess.</p></div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="install wrap" id="installation">
|
|
<div class="sect"><h2>Installation</h2><span>Node 18+ · network required · re-run to update</span></div>
|
|
<div class="termwrap">
|
|
<pre class="term" id="install-cmd"><span class="p">$</span> npx <span class="k">--allow-git=all</span> git+https://github.com/jparkerweb/plan2code.git</pre>
|
|
<span class="copy-flash" id="copy-flash" aria-hidden="true">Copied</span>
|
|
<button class="copy" id="copy-btn" type="button" aria-label="Copy install command to clipboard" title="Copy install command">
|
|
<svg class="clip" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
<svg class="tick" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 12.5 9.5 18 20 6.5"/></svg>
|
|
</button>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="close">
|
|
<div class="wrap">
|
|
<h2>Post it once.<br><em>Then go outside.</em></h2>
|
|
<span class="hand">free, MIT, twenty seconds to install</span>
|
|
<br><a class="btn" href="https://github.com/jparkerweb/plan2code">Plan2Code Git Repo</a>
|
|
</div>
|
|
</section>
|
|
|
|
<footer><div class="wrap"><span>Plan2Code v2.0.0</span><span>MIT</span><span>plan2code.jparkerweb.com</span></div></footer>
|
|
|
|
<script>
|
|
(function(){
|
|
var CMD = 'npx --allow-git=all git+https://github.com/jparkerweb/plan2code.git';
|
|
var btn = document.getElementById('copy-btn');
|
|
var flash = document.getElementById('copy-flash');
|
|
var timer;
|
|
function done(){
|
|
btn.classList.add('-done');
|
|
flash.classList.add('-on');
|
|
clearTimeout(timer);
|
|
timer = setTimeout(function(){
|
|
btn.classList.remove('-done');
|
|
flash.classList.remove('-on');
|
|
}, 1800);
|
|
}
|
|
function fallback(){
|
|
var ta = document.createElement('textarea');
|
|
ta.value = CMD;
|
|
ta.setAttribute('readonly','');
|
|
ta.style.position = 'fixed';
|
|
ta.style.opacity = '0';
|
|
document.body.appendChild(ta);
|
|
ta.select();
|
|
try { document.execCommand('copy'); done(); } catch(e) {}
|
|
document.body.removeChild(ta);
|
|
}
|
|
btn.addEventListener('click', function(){
|
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
navigator.clipboard.writeText(CMD).then(done, fallback);
|
|
} else {
|
|
fallback();
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|