vinary-viewer is a reactive desktop document previewer built in ClojureScript with re-frame on Electron. You point it at a file (
vv README.md), and it shows a live, always-current preview: edit the file in any editor and the rendered view refreshes the instant you save — without losing your scroll position, your in-page search, or your theme. It previews Markdown (GitHub-flavoured, with heading anchors, syntax highlighting, and embedded SVG figure sizing), images, PDFs, Office/OpenDocument files, Org-mode and LaTeX documents, diffs/patches, workbooks and delimited tables, large logs, archives, source files, plain text, and HTTP/HTTPS links, across multiple tabs, with a git file tree, an in-page find, a table-of-contents scroll-spy, navigation history, live theme switching, and custom keybindings. Files open locally or overssh:///sftp://, and preview in the desktop GUI or the terminal (vv --clifor a one-shot render,vv --tuifor an interactive pager).
| Field | Value |
|---|---|
| Version | 0.3.0-dev — ClojureScript / re-frame / Electron rewrite (package.json) |
| Predecessor | 0.1.0 was a vmd-patching tool; that codebase is superseded and preserved at git tag v0.1.0 |
| Live runtime | src/vinary/** (ClojureScript) + resources/** (preload.js, public/) |
| Build | shadow-cljs five builds — GUI (:main → Electron main; :renderer → Chromium), terminal (:cli, :tui), and the DOM-free :test build |
This suite documents the live 0.3.0-dev application. Capabilities are
tagged so you can distinguish current behavior from intentionally future work:
- Available now — implemented in
src/vinary/**andresources/**. - Forthcoming (planned) — designed but not built. At the time of this
revision, source-diagram rendering from
.d2,.puml,.mmd, and.dotfiles is still planned; those files currently open in the read-only source preview. Some older pages and diagrams keepplannedin their filename because they began as design documents, but their status text is authoritative.
Anything not explicitly tagged Forthcoming is Available now.
The use-case diagram below partitions the feature set into Available now
(teal) and Forthcoming (planned) (dashed grey). Source:
diagrams/usecase-features.puml.
Pick the path that matches your goal. Each path lists the documents in the order they build on one another.
"I just want to use it" → start in usage/
usage/01-getting-started.md— first preview in under a minute.usage/02-installation-and-build.md—shadow-cljscompile/watch/release and running under Electron.usage/03-opening-files-and-tabs.md— command-line argument, the git tree, multi-tab browsing.usage/04-keyboard-shortcuts.md— the default keys (Ctrl+F,Alt+←/→) and the vim/emacs custom-keybinding system.usage/05-configuration.mdandusage/06-troubleshooting.md.
For a feature-by-feature catalogue (one page each), see
features/.
"I want to understand why it is built this way" → theory/, then architecture/
The theory pillar explains the ideas — the patterns, the data model, the invariants — independent of any one file. Read it in order:
-
theory/01-reactive-architecture.md— unidirectional data flow; re-frame's six dominoes mapped onto the Command and Observer patterns; the single-source-of-truth equation$\mathrm{view} := f(\mathrm{state})$ . -
theory/02-state-model-datascript-app-db.md— the two stores (app-dbfor tabs/history and UI; DataScript for the bounded content cache), the minimal schema, and the:ds/revbridge that ties them together. -
theory/03-live-refresh-spine.md— the flagship spine: editor-save → painted DOM, and the invariant that a content refresh mutates only:doc/*, never:ui/*. -
theory/04-hexagonal-and-ipc-mediator.md— ports & adapters, effects at the edge, and the MediatorcontextBridgeIPC seam. -
theory/05-strategy-renderer-registry.md— the Strategy that picks a document body by:doc/kind. -
theory/06-find-css-custom-highlight.md— painting search matches as Ranges with the CSS Custom Highlight API, without touching the DOM. -
theory/07-command-history-model.md— navigation as reified Commands on a{:stack :idx}history. -
theory/08-common-document-ir.md— one weighted-transducer IR every format parses into; semiring/WPDA/transducer core. -
theory/09-document-streaming-and-the-wpda.md— treating a document as a bounded-memory stream; the WPDA log grammar; the bounded-memory property. -
theory/10-terminal-rendering-second-renderer.md— the terminal (vv-cli/vv-tui) as a second renderer over the same IR and streaming spine; ANSI back-end, kitty/sixel graphics, headless PDF reflow.
Then read the architecture pillar for the concrete realisation:
architecture/01-overview.md,02-process-and-build-topology.md,03-ipc-protocol.md,04-state-schema-reference.md,05-data-flows.md,06-renderer-runtime.md.
"I want to contribute" → architecture/ + engineering/ + reference/ + design-decisions/
- Architecture as above for the lay of the land, including
architecture/07-common-ir-streaming-and-terminal.mdfor the concrete IR/streaming/terminal component map. engineering/— how the project is built, tested, released, and contributed to: the five builds, asset vendoring, the test taxonomy, lint/conventions, the release process, the doc/diagram gates, and the contribution workflow (00…10).reference/— the tables you keep open while coding:events-effects-subs.md,ipc-channels.md,css-variables.md,namespaces.md.design-decisions/— the numbered ADR-style log (0001…0027) recording why each pivotal choice was made: rendering in the renderer, the hand-rolled:ds/revbridge over re-posh, imperativeinnerHTMLover VDOM, the IPC mediator, bounded content retention, the common document IR, the streaming pipeline, the terminal second-renderer, Org/LaTeX/diff, and remote SSH.scientific/— how correctness is verified: byte-parity, bounded-memory validation, semiring laws, sanitizer context-freedom, and the recorded experiments (00…07).security/threat-model.md— the Electron security posture and recommended hardenings.
Every document in the suite, with its pillar and one-line purpose.
| Document | Pillar | What it covers |
|---|---|---|
README.md |
entry | This index, status, reading paths, conventions |
GLOSSARY.md |
entry | Every term, acronym, and symbol, defined once |
theory/01-reactive-architecture.md |
theory | Unidirectional flow; six dominoes; Command + Observer; |
theory/02-state-model-datascript-app-db.md |
theory | Two stores; app-db tabs/history; DataScript content cache; :ds/rev bridge; nil-as-absence |
theory/03-live-refresh-spine.md |
theory | The save→render→paint spine; the :doc/*-only invariant; convergence/LWW |
theory/04-hexagonal-and-ipc-mediator.md |
theory | Ports/adapters; effects at the edge; the Mediator contextBridge seam |
theory/05-strategy-renderer-registry.md |
theory | Strategy-by-:doc/kind; content-view precedence; future registry-as-data |
theory/06-find-css-custom-highlight.md |
theory | Painting Ranges without DOM mutation; collect-ranges/paint!/cycle!
|
theory/07-command-history-model.md |
theory | Navigation as Commands; {:stack :idx}; truncate-on-new-path |
theory/08-common-document-ir.md |
theory | One tagged IR per format; semiring/WPDA/tree-transducer; single sanitizer; byte-parity |
theory/09-document-streaming-and-the-wpda.md |
theory | Document as a bounded-memory stream; WPDA log grammar; StreamParser; append sink |
theory/10-terminal-rendering-second-renderer.md |
theory | Terminal as a second renderer over the shared IR/streaming spine; ANSI back-end; kitty/sixel |
architecture/01-overview.md |
architecture | System-level component map |
architecture/02-process-and-build-topology.md |
architecture | Two Electron processes; the two shadow-cljs builds |
architecture/03-ipc-protocol.md |
architecture | The vv:* channels and payload shapes |
architecture/04-state-schema-reference.md |
architecture | DataScript schema + full app-db shape |
architecture/05-data-flows.md |
architecture | Open / refresh / find / history flows end-to-end |
architecture/06-renderer-runtime.md |
architecture | Renderer boot order, reagent mount, dev hooks |
architecture/07-common-ir-streaming-and-terminal.md |
architecture | Concrete IR / streaming / terminal component realization |
design-decisions/README.md + 0001…0027
|
design | Why each pivotal choice was made (ADRs) |
engineering/00..10 |
engineering | Build system, asset vendoring, test strategy, lint, release, CI, contribution, bounded-memory |
scientific/00..07 |
scientific | Byte-parity, bounded-memory validation, semiring laws, sanitizer context-freedom, experiments, methodology |
usage/01..08 |
usage | Getting started, install/build, files & tabs, shortcuts, config, troubleshooting, terminal CLI/TUI, remote SSH |
features/README.md + 01…30
|
features | One page per feature (live refresh … LaTeX, diff, remote SSH, terminal preview) |
reference/events-effects-subs.md |
reference | Every re-frame event, effect, subscription |
reference/ipc-channels.md |
reference | Every IPC channel, direction, payload |
reference/css-variables.md |
reference | The --vv-* design tokens |
reference/namespaces.md |
reference | Every ClojureScript namespace and its role |
security/threat-model.md |
security | Electron isolation posture; recommended hardenings |
diagrams/ |
diagrams | All PlantUML sources + the shared theme |
These conventions are shared by every document. They exist so the suite reads as one coherent whole.
-
Term-before-use. Every acronym, symbol, and domain term is defined the first time it appears, and again — canonically — in
GLOSSARY.md. When a term is first introduced, the glossary records which document introduced it. -
Mathematics is MathJax, delimited for GitHub-flavoured Markdown. A formula is a math span, never an inert code span and never a string of Unicode glyphs. Two forms, and only these two:
-
Inline — a backtick span wrapped in dollar signs, e.g. the single-source-of-truth equation
$\mathrm{view} := f(\mathrm{state})$ , or the find cursor$\mathit{idx}' := (\mathit{idx} + \mathit{dir}) \bmod n$ . -
Display — a fenced block whose info-string is
math, e.g. the history push:\mathit{stack}' := \mathtt{(conj\ (vec\ (take\ (inc\ idx)\ stack))\ path)}
Never write bare
$…$or$$…$$. GitHub's CommonMark pass strips backslash escapes before MathJax ever sees them, so those delimiters corrupt an expression — sometimes loudly, sometimes silently. Write a literal dollar sign as a code span, and never let an ASCII letter abut the opening delimiter.The operator
:=reads "is defined as"; a prime, as in$\mathit{stack}'$ , denotes the next value of a binding after an update.Unicode remains correct for non-mathematical text — box-drawing, arrows, enumerations, and separators such as
events · subs · fx. -
-
Diagrams are PlantUML. Every diagram lives under
diagrams/as a.pumlfile that begins with@startumland!include _vv-theme.iuml. Each file's header comment states why PlantUML was chosen over Mermaid for that illustration. Documents embed the rendered.svgimage and cite the.pumlsource path, so the figure is visible in ordinary Markdown viewers while remaining one click from its source. -
Color legend. Colours are per-concept and stable across the whole suite — a colour always means the same thing. The palette is defined once in
diagrams/_vv-theme.iumland is drawn from the app's own Spacemacs--vv-*tokens. Each concept owns one hue; the accent below is that hue at full saturation. The mapping:Colour Accent hex Concept ▮ Slate #3A5BA0Main process (Node IO) ▮ Teal #2D9574Renderer / Chromium / reagent view ▮ Amber #B1951DIPC seam (preload, contextBridge, Mediator) — all IPC arrows are amber▮ Purple #A45BADDataScript single source of truth ▮ Blue-violet #7590DBapp-db ephemeral UI state ▮ Blue #4F97D7re-frame machinery (events, fx, subs) ▮ Tan #9F8766Filesystem / editor (chokidar) ▮ Green #67B11DMarkdown (unified / remark / rehype) ▮ Magenta #BC6EC5Keymaps (registry, key-binding editor, link hints) ▮ Orange #E67E22Common document IR core (semiring · transducer · WPDA) ▮ Red #E0211DErrors / retractions ▯ Dashed grey #DDDDDDForthcoming (planned) — «planned»stereotypeHue names the concept; lightness names the role. The accents are foreground colours — legible as ink or as a small swatch, overwhelming as a large area fill. So each concept exists at four tiers, and which one you use is decided by role, never by taste:
Macro Tier Used for <CONCEPT>_FILLpalest package / container backgrounds <CONCEPT>_TINTmid component, participant, state and object fills <CONCEPT>_BORDERdark arrow strokes for that concept <CONCEPT>_COLORaccent legend swatches only — never an area fill _FILLand_TINTare derived from_COLORby moving lightness and saturation in HLS space with the hue held fixed, so the whole palette is reconstructible from the eleven accents alone. Every_FILLand_TINTclears WCAG 2.x AA against the ink#1A1A1Aby at least10.8:1.Every diagram repeats a
legendmapping its accents to concepts, so each is self-contained. Seediagrams/README.mdfor the full diagram catalogue, the tier derivation, and the render-time regression gates. -
Citations. Sources are cited inline with a link, and DOIs are used only when they resolve — see
GLOSSARY.mdand each document's References section. Foundational design-pattern claims cite Design Patterns (Gamma, Helm, Johnson & Vlissides, 1994, ISBN 978-0201633610 — this book has no DOI). The Model-View-Controller lineage cites Krasner & Pope (1988) by its ACM Digital Library landing page,dl.acm.org/doi/10.5555/50757.50759. Despite its shape,10.5555/50757.50759is not a registered DOI —10.5555is ACM's placeholder prefix for pre-DOI material, anddoi.org/10.5555/50757.50759returns HTTP 404. Cite it as a library link, not as a DOI. Library and platform claims cite the projects' official documentation.
vinary-viewer is original work licensed Apache-2.0, a new application
inspired by vmd (MIT). The full
attribution and third-party notices live in the repository NOTICE file and in
design-decisions/README.md. Author: Vinary Tree
<dylon@vinarytree.io>.