Skip to content

Repository files navigation

binos

A small, self-contained markdown previewer written in Go. Point it at a .md file or a folder. It opens a rendered preview in your browser, with mermaid and d2 diagrams and live reload on save.

binos example.md

binos previewing example.md, split diagonally between light mode (upper left) and dark mode (lower right)

Important

This project was almost entirely AI generated.

Features

  • GitHub-flavored markdown. Tables, task lists, strikethrough, and autolinks.
  • Syntax highlighting for fenced code blocks, via chroma.
  • Mermaid diagrams. ```mermaid blocks render in the browser.
  • D2 diagrams. ```d2 blocks render to SVG on the server. No external d2 binary is needed.
  • Live reload. Save the file and the browser updates in place, keeping your scroll position.
  • Directory tree. A resizable sidebar lists every markdown file under the served folder. Folders collapse, and the current file is highlighted. Each entry shows the document's title with the filename in a small badge. On narrow windows the sidebar becomes a drawer behind a menu button.
  • Table of contents. A column on the right outlines the current document's headings and tracks your position as you scroll. It only appears when the document has more than one heading.
  • Fuzzy file switcher. Press ⌘K or Ctrl-K to jump to any markdown file under the served folder. The search matches both the title and the filename. This is handy for note collections where filenames are IDs.
  • Relative images. ![](pics/photo.png) and similar links are served from the document's folder. Remote and data-URI images work too.
  • Fully offline. Mermaid, the Web Awesome UI components, and all styles and icons are embedded in the binary. Nothing is fetched from the network.

A document's title is its first markdown heading. If there is no heading, a title: key in YAML front matter is used instead. The title appears in the sidebar, the switcher, and the browser tab.

Install

With Homebrew:

brew tap c9rgreen/tap
brew install binos

Or build from source. This needs Go 1.26 or newer, Node 20 or newer, and pnpm (see Frontend dependencies).

# Build a local binary
make build

# Put it on your PATH, e.g.
mv binos /opt/homebrew/bin/      # or ~/.local/bin, etc.

Or install straight to $(go env GOPATH)/bin. Make sure that folder is on your PATH.

make install

A plain go build or go install fails until the frontend has been built once. The make targets above handle that step for you.

Usage

binos [flags] [file.md | directory]
Flag Default Description
--port 0 Port to listen on (0 picks a free one)
--no-open false Don't open the browser automatically

With a file, binos serves that file's folder and opens the file. With a folder, it serves the folder and opens README.md, or the first markdown file if there is no README. With no argument, it serves the current folder. Files ending in .md or .markdown count as markdown. Hidden folders, node_modules, and vendor are skipped.

The server binds to 127.0.0.1 and prints the URL. Press Ctrl+C to stop.

Pages use the Modus palette and follow the system light/dark setting. Diagrams and syntax highlighting follow it too. Printing always uses plain black on white, and hides the sidebar and table of contents.

Note

The previewed files are treated as trusted content. Raw HTML in the markdown is passed through, and d2 diagrams are embedded as inline SVG. The whole served folder is also available over 127.0.0.1 so relative images load. Directory listings are disabled, and paths cannot escape that folder. This is meant for files you wrote. Avoid previewing untrusted markdown.

Diagram examples

A mermaid block:

```mermaid
flowchart LR
    A --> B --> C
```

A d2 block:

```d2
client -> server: request
server -> client: response
```

A syntax error in one diagram shows an inline error box. The rest of the page still renders.

Project layout

main.go                      CLI: flags, free port, browser open
internal/render/render.go    goldmark pipeline + mermaid/d2 interception
internal/render/d2.go        d2 source -> inline SVG
internal/render/title.go     document title from first heading or front matter
internal/server/server.go    HTTP server, SSE live reload, fsnotify watcher
internal/assets/             page template; embeds the frontend bundle and icons
frontend/                    page JS and CSS, bundled with Web Awesome and mermaid
testdata/example.md          sample document

Frontend dependencies

The UI uses mermaid for diagrams, Web Awesome web components, and icons from Font Awesome. All three are pnpm dependencies. Nothing is vendored.

This project requires pnpm. package.json pins the version through packageManager, and a preinstall guard rejects npm and yarn. With corepack: corepack enable pnpm.

The page's own JavaScript and CSS live in frontend/. pnpm run build uses Vite+ to bundle frontend/main.js into internal/assets/dist. Vite+ is the OXC toolchain in one vp command: its build is Vite 8 on Rolldown, minified with oxc-minify, and it also ships Oxlint and Oxfmt. vite.config.js holds the build, lint, and format settings. The bundle contains:

  • The Web Awesome components the page uses, one import per <wa-*> tag. A Go test checks that the import list matches the tags the page emits.
  • Web Awesome's stylesheet and frontend/styles.css.
  • Mermaid. Its per-diagram modules become chunks that load on demand.

The Font Awesome icons listed in the Makefile are copied into internal/assets/icons, because <wa-icon> fetches icons by URL. Both output folders are gitignored and embedded in the binary. They must live under internal/assets because go:embed only sees files inside the package directory.

make frontend runs both steps and installs node_modules on first use. make build, make install, and make test all run it first. A bare go build fails with a no matching files found embed error until make frontend has run once.

Common changes:

  • To use a new Web Awesome component, add its import to frontend/main.js.
  • To add an icon, add it to the ICONS list in the Makefile.
  • To upgrade a package, bump it in package.json and rebuild.

The frontend is checked with three linters. make lint runs them all, and make check runs it after the Go vet and tests.

  • Oxlint lints the JavaScript with its correctness rules as errors and suspicious rules as warnings.
  • Oxfmt checks that the JavaScript, CSS, JSON, and markdown are formatted. make fmt formats them (and runs gofmt), and pnpm run fix also applies Oxlint's safe fixes.
  • stylelint lints the hand-written stylesheet, frontend/styles.css, with stylelint-config-standard plus selector-max-id: 0, so styles use classes and design tokens, never IDs.
make lint
make fmt

License

MIT — see LICENSE.

About

Markdown viewer for files or directories; live reload, mermaid diagrams

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages