diff --git a/AGENTS.md b/AGENTS.md index f5aa3c8..ac0d39b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,7 +46,9 @@ port legacy code. lazy-loads Vega, so `/` stays light. The PWA service worker and manifest are scoped to `/app/`, leaving the landing uncontrolled and always-fresh. **`/learn/` is a second such entry** (`src/learn/`) — the markdown-authored deep-dive section, under the same rules - (see architecture 11). + (see architecture 11). The landing depicts only shipped behavior: live demos run the + real core, and staged visuals (the editor still) mirror the app's actual strings — + CodeLens labels, validation messages — never invented UI. See [`docs/architecture/`](docs/architecture/00-overview.md) for the patterns behind each layer (state, persistence, modals, routing, rendering, inference, relationships) and @@ -147,6 +149,11 @@ Invoke with `/` (defined in `.claude/skills/`): Recurring findings become `docs/architecture/` rules and new `/alignment` checks. - **`/release`** — bump version, update the changelog, prepare a git tag. +### Deployment + +Push to `main` auto-deploys to **astrolabe-viz.com** (Cloudflare Pages, Git-connected). +Hosting, analytics posture, and distribution facts: **[docs/deployment.md](docs/deployment.md)**. + ### Versioning Simplified semver `0.x.y` (pre-1.0): minor for features/behavior, patch for fixes. Single diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 0000000..8eab3dc --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,24 @@ +# Deployment & Distribution + +Operational facts that live nowhere in the code. + +## Hosting + +- **astrolabe-viz.com** runs on **Cloudflare Pages**, project `astrolabe-viz`, + Git-connected to the private GitHub repo `olehomelchenko/astrolabe`. +- **Push to `main` auto-builds and deploys** (`npm run build`; the post-build + `check-light-entries` gate runs as part of it). There are no GitHub Actions. +- Live since 2026-06-20. +- **No analytics.** The app ships no beacon or tracking of any kind; Cloudflare keeps + standard aggregate access logs as any host does. The About modal's privacy copy states + exactly this — keep them in agreement. + +## Distribution posture + +- **Free to use; the code is private.** Astrolabe is not open source. User-facing copy + (landing, About, learn) must never claim or imply otherwise — the open thing is the + _format_ (Vega-Lite JSON), and copy attributes openness to it deliberately. +- **Feedback channel** is the branded address `feedback@astrolabe-viz.com` + (`src/app/feedback.ts`), not a public issue tracker. +- **Release cadence**: unreleased pre-1.0; the first public release is `1.0.0`, cut on + the maintainer's signal (see `docs/IMPLEMENTATION-PLAN.md` and the `/release` skill). diff --git a/docs/exploration/landing-onboarding-scope.md b/docs/exploration/landing-onboarding-scope.md new file mode 100644 index 0000000..3e2ed37 --- /dev/null +++ b/docs/exploration/landing-onboarding-scope.md @@ -0,0 +1,177 @@ +# Landing & Onboarding Scope + +_Point-in-time scope memo, 2026-07-04. Consolidates the onboarding/landing review: audience +model, claims audit, objection map, target landing architecture, and the implementation +phases. Supersedes nothing; feeds the next landing/onboarding sessions._ + +_Status (2026-07-04, same session): **Phases 1 and 2 shipped** — deep links, paste door, +learn links, brushed-scatter example, and the full landing overhaul (showcase block, +editor proof, objection beats, reweighted blocks, trust creed, voice pass). Phase 3 +(learn growth) remains. Gotcha recorded at the code site: faceted/concat specs need +`fitMode: 'default'` in `LandingChart` — the width-fit contract can't size their +children._ + +## Audience & thesis + +The goal of the public surfaces is to **popularize Vega-Lite's capabilities**, not to serve +a niche. Two audiences, one page, two pitches: + +- **Beginners / the declarative-curious** — sold on **Vega-Lite itself**: charts written as + text, interactive by declaration, beautiful out of the box (something users rarely have + time to achieve themselves). Their doors: the Chart Builder, examples, `/learn/`. +- **Practitioners** (already write specs, often via wrappers) — sold on **the editor**: a + home for specs (vs. the Vega editor's scratchpad), schema-aware Monaco, dataset library, + themes/fonts, export parameters the vega-embed kebab menu never offers. + +The surface stays **general-purpose**: learners are welcome underneath, but nothing reads +as a teaching tool or classroom product. Blocks alternate between the two pitches; the +strongest moves serve both at once (a themed, interactive chart sells VL capability to the +beginner and the theming machinery to the practitioner in the same pixels). + +Hero-copy consequence: "A home for your Vega-Lite charts" addresses only people who +already have Vega-Lite charts. The headline must admit the beginner too — positive case +first (charts as text: interactive, themeable, durable), "home for them" as the second +beat. + +## Claims audit (2026-07-04) + +Every claim on the current landing verifies against the code — no overclaims. The page +**underclaims**: shipped capabilities absent from it, in order of missed leverage: + +1. **Interactivity** — the page contains zero interactive charts (live-rendered, yes; + interactive, no), while interactivity is VL's headline capability for popularization. +2. **Composition wireframe** — drag-editable multi-view editing; unique in the Vega + ecosystem; unmentioned. +3. **Data inspector** — input vs. resolved rows per view; the answer to "why is my chart + empty"; unmentioned. +4. **CodeLens scaffolds** — one-click working params/transforms/view blocks; the bridge + feature (beginners get working code to study, practitioners get speed); unmentioned. +5. **Theme Builder breadth** — landing lists colour/type/axes/legend/layout; it also does + marks, titles, number formats. +6. **`/learn/`** — a capability, currently only a nav link. + +Nitpick: "Sixteen presets" counts "Stock Vega-Lite (no theme)" as a preset. + +Page-wide visual finding: nearly every chart renders in default blue. The page's imagery +_is_ its charts; they must carry themed variety — the page itself is the proof of +"out-of-the-box beauty without the time investment". + +Pacing findings (desktop 1440, light): theme block ≈ a quarter of total scroll (three +tall charts stacked); builder demo's default state is the most boring chart it can produce +(count-by-channel, plain blue); datasets — the core "home, not scratchpad" argument — gets +the weakest visual (small static mock); export gets a full peer block for what is partly +table-stakes; the hero app window reads as a screenshot (nothing signals it is live). + +## Objection map + +Objections cluster two ways; each gets **one compact moment** on the page, not a FAQ +sprawl. The best answers are either **on-ramps** or **stances stated before suspicion +forms**. + +**Habit cluster** — "I already have a way" — one positioning block near the editor +section: + +- _Vega editor?_ A scratchpad, not a home. (One-slot, no library, no fonts/themes.) +- _Altair / wrappers?_ Their output **is** a Vega-Lite spec — paste it in, polish, keep. + Most real-world VL usage is via Altair; this is the largest single objection. Nobody + hand-writes specs from a blank buffer, and Astrolabe never asks them to (examples, + builder, paste + autocomplete/scaffolds/inspector). Last-mile polish (label exprs, axis + formats) is often faster in the spec than translated back through a wrapper API. +- _LLMs write specs?_ Yes — paste it here; this is where an almost-right spec gets + diagnosed (preview, validation, inspector). AI-free is a privacy feature: the model + never sees the real data. + +**Trust cluster** — generated by the local-only stance itself — lives at/near the creed: + +- _Local = fragile?_ The library exports as one JSON file; back it up like any file you + own. Copy must stay on export/import — never imply sync (none exists). +- _Closed source, so why believe "no data leaves"?_ Falsifiable claim instead: static + site, no backend, works fully offline once installed — airplane mode is the audit. + (Never claim open source.) +- _Solo project longevity?_ Lock-in-free is the honest answer: everything is ordinary + Vega-Lite JSON; specs outlive the tool; the PWA keeps working offline. +- _Sharing?_ Exports are the sharing story; spec-with-data-inlined is quietly the share + feature and should be framed as one. + +Beginner-adjacent beat (one line, no comparison table): vs. Datawrapper/Flourish — no +account, no hosting dependency, real interactivity, a growing library you own. + +**Deliberately not addressed on the landing**: storage limits / huge datasets (real +constraint, edge concern; the in-app storage monitor is the right surface — raising it in +marketing plants a worry most visitors never had). + +## Target landing architecture + +1. **Hero + app window** — dual-audience headline; default example themed and + interactive; explicit "this is the real app — try it" affordance; window's snippets + deep-link into the app. +2. **"What Vega-Lite can do"** — NEW, the popularization centerpiece: 2–3 interactive + charts (tooltip; brush → linked filter; a facet) in distinct themes, each beside its + short spec. Argument: _this is a text file._ +3. **"A serious editor"** — practitioner proof: autocomplete/validation/inline docs + shown (staged, NOT real Monaco — the post-build gate keeps Monaco off the landing), + CodeLens scaffold shown, data inspector named. Positioning block (habit cluster) + attaches here. +4. **"Don't want to start from JSON?"** — builder, explicitly the second door; demo + defaults to a colourful non-trivial state (an intent applied, colour encoding on). +5. **"One library"** — datasets promoted and made vivid (extract-inline-data + before/after is the honest demo). +6. **"Make it yours"** — half current height: one chart + theme switcher, gallery as a + compact grid, fonts in the first sentence. +7. **"Get it out the way you need it"** — export reframed as practitioner pain relief + (parameters the vega-embed kebab menu lacks), compact; inline-data export framed as + sharing. +8. **Creed** — plus the trust cluster (backup/export, offline-as-proof, portability-as- + longevity) → learn pointer → close. + +Verify on mobile and dark before committing layout. + +## App-side changes + +- **Deep links in**: `#build` already exists in the hash grammar — the landing builder + demo can link today. Add `#example-` (consumed once at startup: create that + example as a snippet, open it, clear the param) so landing demos hand off momentum + instead of resetting at the onboarding canvas. Spec §01 hash table updates with it. +- **Onboarding canvas third door — "Paste a spec"**: serves Altair users, LLM users, + Vega-editor migrants; today they must Create → select-all → delete → paste. Also a + quiet "Restoring from an export? Import your workspace" line (Import is header-icon-only + during onboarding). Spec §02 updates. +- **Example gallery showpieces**: add 1–2 interactive/composed examples (brushable + scatter + linked histogram; ties to the existing linked-views lesson). Single source of + truth pays twice: the landing hero window shows them automatically. +- **Learn wiring**: the app currently has zero links to `/learn/`. Add: About modal, and + a low-key onboarding-canvas line. + +## Learn direction + +- Lessons gain "Open in Astrolabe" (mechanism: example ids where possible; arbitrary + stage specs need a spec-payload deep link — decide at implementation, watch hash size). +- Content growth (later): lessons keyed to examples ("what to try next with the + scatter"), draft/publish workflow, theming walkthrough. Until grown, keep nav billing + consistent with a two-lesson section. + +## Implementation phases + +**Phase 1 — connective tissue (app-side, one session):** +`#example-` deep link (core parse + startup consumption + tests) · paste-a-spec door +(+ import line) on the onboarding canvas · learn links (About + canvas) · showpiece +example(s) in `CHART_EXAMPLES` with compile test · spec §01/§02 updates in-session. + +**Phase 2 — landing overhaul (design-involved):** +New showcase block (#2) first — it is the thesis · editor-proof block (#3, staged +visuals, no Monaco import) · resequence/reweight (#4–#7) · hero copy + live-affordance · +objection + trust beats · themed-chart pass across every chart on the page · mobile/dark +pass. + +**Phase 3 — learn growth (ongoing content):** +"Open in Astrolabe" from lessons · new lessons per the direction above. + +## Parked / deferred + +- Post-first-snippet discoverability (draft/publish, extract, theming are invisible until + stumbled on; no tours — against the app's grain) → parked in `docs/ux-second-pass.md` + for the batched council pass. +- Multi-device sync → separate exploration (see monetization/sync memo); landing copy + must not imply it. +- URL-encoded spec sharing (à la Vega editor) → plausible future feature if the sharing + objection keeps surfacing; product, not copy. diff --git a/docs/exploration/vscode-extension.md b/docs/exploration/vscode-extension.md new file mode 100644 index 0000000..23cf673 --- /dev/null +++ b/docs/exploration/vscode-extension.md @@ -0,0 +1,71 @@ +# VS Code / Positron Extension — Exploration + +_Point-in-time memo, 2026-07-04. Option recorded for post-1.0; nothing is being built. +Assesses shipping Astrolabe's authoring intelligence as an editor extension._ + +## The idea + +Port the editor-intelligence layer — scaffolding CodeLenses, spec-aware completions, the +data inspector, live preview — to a VS Code extension (and Positron via OpenVSX), working +on `.vl.json` files in the user's own workspace. + +## Why it's cheap: the core/adapter boundary + +Everything interesting is already editor-agnostic. `src/core/` (spec analysis, scaffold +construction, site detection over JSON offsets, rendering preparation) has no Monaco +imports; the Monaco layer (`spec-param-scaffold`, `spec-transform-scaffold`, +`editor-cursor-lens`) is thin adapters. VS Code's extension API has one-to-one +counterparts: + +| Astrolabe piece | VS Code counterpart | +| ------------------------------- | ---------------------------------------------------- | +| CodeLens scaffolds | `languages.registerCodeLensProvider` + core verbatim | +| Param/transform completions | `registerCompletionItemProvider` / code actions | +| Live preview (`chart-renderer`) | Webview panel running vega-embed (same browser ctx) | +| Data inspector (`inspectData`) | Same webview, message bridge to the render handle | +| Bundled schema (offline) | `jsonValidation` contribution | +| Dataset-by-name (`data.name`) | Resolve against a workspace `datasets/` folder | + +Both editors expose offset↔position conversion, so the core's offset-based site +detection transfers without change. + +## The marketplace gap + +Preview exists; authoring help does not. + +- [Vega Viewer](https://marketplace.visualstudio.com/items?itemName=RandomFractalsInc.vscode-vega-viewer) + and [Vega Preview](https://marketplace.visualstudio.com/items?itemName=mdk.vega-preview) + render specs — preview-only. +- The [official vega plugin](https://github.com/vega/vega-vscode) is deprecated; its note + points out VS Code's built-in JSON service already gives `$schema`-driven completion and + validation. **Schema completion/validation are therefore table stakes in VS Code, not + differentiators** — unlike on the web, where Astrolabe had to build them. +- Nothing in the marketplace offers scaffolds, an input-vs-resolved data inspector, + dataset references, or theme configs. + +Positron (Posit's VS Code fork, OpenVSX-distributed) concentrates the Altair audience — +people whose wrapper output is already Vega-Lite and who live in an editor. For them an +extension is more native than any website. + +## v1 scope, if built + +In: bundled-schema validation (offline), scaffold CodeLenses (params/transforms), live +preview panel, data inspector, `data.name` resolution against a workspace folder, theme +as an apply-able config file. Out, deliberately: the library, drafts/publish (git covers +it), the chart builder UI, the theme builder, fonts UI. The extension is "Astrolabe's +authoring intelligence, detached" — the _home_ identity does not port, because in an +editor the workspace already is the home. + +## Strategic read + +For: real organic discovery (people search "vega" in the marketplace; nobody web-searches +for a snippet manager they don't know exists); every extension user is a lead for the +app; the port validates the core-first architecture. + +Against: a second product surface for a single maintainer; it showcases the commodity +part of Astrolabe (editing) rather than the unique part (the home); Positron/OpenVSX +publishing is an extra channel to maintain. + +**Decision: defer until after the web app's 1.0.** The only standing cost of keeping the +option open is one we already pay by conviction: keep `src/core/` free of editor and +browser imports. diff --git a/knip.json b/knip.json new file mode 100644 index 0000000..a3edba9 --- /dev/null +++ b/knip.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://unpkg.com/knip@5/schema.json", + "ignoreDependencies": ["@fontsource/.*", "@fontsource-variable/.*", "marked"] +}