f1011d7f6f
The landing page is the site root and the app is /app/; the prose now sits at /docs/, assembled by the same web/assemble.sh the Pages job and the browser harness both run, so what ships and what is tested are one tree. Published: design-notes, design-principles, repo-map, the three ADRs, the seven context/code/ arguments, and the 501 test-evidence entries as their own clearly-labelled section. Not published: context/plan.md, which is an agent prompt about a launch rather than a description of the program, and context/cloud-agents.md, which is addressed to nobody who visits a website. Neither is referenced by a published document outside a code fence, so leaving them out dangles nothing. The reasoning is context/code/doc-site.md, which is itself published. Two things the corpus needed that a generator would not have given it. The ~190 improvise-xxxx citations resolve to a generated ticket index built from the already-public .beads/issues.jsonl rather than to an invented URL that would 404; an id the export does not yet carry stays plain text. And a code span that is wholly a repo path links to GitHub at the assembled ref, but only when the file exists on disk, so a stale citation degrades to text. The generator link-checks its own output and exits non-zero on a break, and assemble.sh runs under set -eu, so a dead cross-reference fails the assembly rather than shipping. It earned that on its first two runs: it caught a fence-close regex comparing a three-character marker to a one-character string, which swallowed every document from its first code block onward, and a list parser that ended the gotcha list at the first blank line, emitting 1 of the 48 anchors the jump strip links to. Proved by injection afterwards -- renaming the anchors reports 48 missing anchors, pointing the ticket links at an ungenerated page reports 763 missing pages. No framework, no node_modules for the site, no build step beyond one zero-dependency node script, matching the landing page's posture. improvise-djoo Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
216 lines
6.7 KiB
HTML
216 lines
6.7 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>improvise — terminal pivot-table modeling</title>
|
|
<meta
|
|
name="description"
|
|
content="Terminal pivot-table modeling in the spirit of Lotus Improv: multidimensional cells, formulas over dimensions instead of cell addresses, vim-style keybindings."
|
|
/>
|
|
<!-- improvise-e61: the site root, linking to the app under ./app/.
|
|
Why cols/rows are 120x37 and not the 100x30 the tickets name: see the
|
|
close reasons on improvise-e61 and improvise-kh8. -->
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdn.jsdelivr.net/npm/asciinema-player@3.10.0/dist/bundle/asciinema-player.min.css"
|
|
/>
|
|
<style>
|
|
:root {
|
|
--bg: #14161a;
|
|
--panel: #1b1e24;
|
|
--fg: #d7dae0;
|
|
--dim: #8b93a1;
|
|
--accent: #8ec07c;
|
|
--rule: #2b2f37;
|
|
--mono: ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace;
|
|
}
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
body {
|
|
margin: 0;
|
|
background: var(--bg);
|
|
color: var(--fg);
|
|
font: 16px/1.6 system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
}
|
|
main {
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
padding: 3rem 1rem 5rem;
|
|
}
|
|
h1,
|
|
h2 {
|
|
font-family: var(--mono);
|
|
font-weight: 600;
|
|
letter-spacing: -0.01em;
|
|
}
|
|
h1 {
|
|
font-size: 2.4rem;
|
|
margin: 0 0 0.4rem;
|
|
color: var(--accent);
|
|
}
|
|
h2 {
|
|
font-size: 1.15rem;
|
|
margin: 3rem 0 0.3rem;
|
|
padding-top: 1.5rem;
|
|
border-top: 1px solid var(--rule);
|
|
}
|
|
.tagline {
|
|
color: var(--dim);
|
|
font-size: 1.1rem;
|
|
max-width: 62ch;
|
|
margin: 0 0 1.5rem;
|
|
}
|
|
p.note {
|
|
color: var(--dim);
|
|
margin: 0 0 1rem;
|
|
max-width: 72ch;
|
|
}
|
|
/* Same size as the body text and set off, not a grey footnote: a
|
|
visitor who reads the section reads this (improvise-2oxt). */
|
|
p.dated {
|
|
margin: 0 0 1rem;
|
|
padding: 0.6rem 0.9rem;
|
|
max-width: 72ch;
|
|
border-left: 3px solid var(--accent);
|
|
background: var(--panel);
|
|
}
|
|
a {
|
|
color: var(--accent);
|
|
}
|
|
.cta {
|
|
display: inline-block;
|
|
margin: 0 0.6rem 0.6rem 0;
|
|
padding: 0.55rem 1.1rem;
|
|
border: 1px solid var(--rule);
|
|
border-radius: 6px;
|
|
background: var(--panel);
|
|
font-family: var(--mono);
|
|
text-decoration: none;
|
|
}
|
|
.cta:hover {
|
|
border-color: var(--accent);
|
|
}
|
|
.cta.primary {
|
|
border-color: var(--accent);
|
|
color: var(--bg);
|
|
background: var(--accent);
|
|
font-weight: 600;
|
|
}
|
|
.player {
|
|
background: var(--panel);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
}
|
|
pre {
|
|
background: var(--panel);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 6px;
|
|
padding: 1rem;
|
|
overflow-x: auto;
|
|
font-family: var(--mono);
|
|
font-size: 0.9rem;
|
|
}
|
|
footer {
|
|
margin-top: 3rem;
|
|
padding-top: 1.5rem;
|
|
border-top: 1px solid var(--rule);
|
|
color: var(--dim);
|
|
font-size: 0.9rem;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<h1>improvise</h1>
|
|
<p class="tagline">
|
|
Terminal pivot-table modeling in the spirit of Lotus Improv —
|
|
multidimensional cells, formulas over dimensions instead of cell
|
|
addresses, and vim-style keybindings for reassigning axes on the fly.
|
|
</p>
|
|
<p>
|
|
<a class="cta primary" href="./app/"
|
|
>▶ Run improvise in your browser</a
|
|
>
|
|
<a class="cta" href="./docs/">Documentation</a>
|
|
<a class="cta" href="https://github.com/fiddlerwoaroof/improvise"
|
|
>Source on GitHub</a
|
|
>
|
|
</p>
|
|
<p class="note">
|
|
No install, no server, no account: the whole application runs in a Web
|
|
Worker on this machine and the document lives in your browser's private
|
|
storage.
|
|
</p>
|
|
|
|
<h2>Reassign an axis</h2>
|
|
<p class="note">
|
|
A category lives on exactly one axis. Moving it rewrites the grid;
|
|
nothing in the data or the formulas changes.
|
|
</p>
|
|
<div class="player" id="cast-pivot"></div>
|
|
|
|
<h2>Drill into an aggregate</h2>
|
|
<p class="note">
|
|
An aggregated cell opens onto the records behind it, editable in place.
|
|
</p>
|
|
<p class="dated">
|
|
Recorded 2026-04-09. The records grid has changed since: it now has a
|
|
column per measure plus columns for adding a category and a measure,
|
|
where this recording shows a single <code>Value</code> column.
|
|
</p>
|
|
<div class="player" id="cast-drill"></div>
|
|
|
|
<h2>Formulas over dimensions</h2>
|
|
<p class="note">
|
|
<code>Profit = Revenue - Cost</code> names categories and items, not
|
|
<code>B3</code>, so it survives every rearrangement of the view.
|
|
</p>
|
|
<div class="player" id="cast-formulas"></div>
|
|
|
|
<h2>Import a CSV</h2>
|
|
<p class="note">
|
|
The wizard classifies each column as a category, a measure or a time
|
|
field, and builds the model from what you confirm.
|
|
</p>
|
|
<div class="player" id="cast-import"></div>
|
|
|
|
<h2>Install</h2>
|
|
<pre>
|
|
# Nix
|
|
nix profile install github:fiddlerwoaroof/improvise
|
|
|
|
# Prebuilt binaries (Linux x86_64/aarch64, macOS Intel and Apple Silicon)
|
|
# https://github.com/fiddlerwoaroof/improvise/releases</pre
|
|
>
|
|
<p class="note">
|
|
Not yet on crates.io; see the releases page for the current prerelease.
|
|
</p>
|
|
|
|
<footer>
|
|
Apache-2.0 ·
|
|
<a href="https://github.com/fiddlerwoaroof/improvise">GitHub</a> ·
|
|
<a href="./app/">Live browser demo</a> ·
|
|
<a href="./docs/">Documentation</a>
|
|
</footer>
|
|
</main>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/asciinema-player@3.10.0/dist/bundle/asciinema-player.min.js"></script>
|
|
<script>
|
|
// One loop rather than four copies of the same call: the config is the
|
|
// same for every cast and a second spelling of it is a second answer.
|
|
for (const name of ["pivot", "drill", "formulas", "import"]) {
|
|
AsciinemaPlayer.create(
|
|
`./casts/${name}.cast`,
|
|
document.getElementById(`cast-${name}`),
|
|
// No idleTimeLimit: every cast header already carries 2.0, and a
|
|
// second spelling of it here is a second answer to one question.
|
|
{ cols: 120, rows: 37, theme: "monokai", autoPlay: false, loop: true },
|
|
);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|