Open to Backend, GenAI & Full-Stack roles · remote or Hyderabad

Projects

Tooling & Lab

nh-deck

Local-first CLI that turns one Markdown file into a presentable slide deck

3 min read · 639 words

View repo 58 commits updated 2 days ago
TypeScript Node.js Commander marked puppeteer-core KaTeX Mermaid highlight.js Vitest GitHub Actions

nh-deck is a TypeScript/Node command-line tool that turns a single Markdown file into a slide deck, for one author who wants to write, present and export slides without an account or a network. It is a solo project: 53 of its 58 commits are the owner's, the other five are Dependabot's.

  • Six subcommands — init, list-themes, render, pdf, png and build, built with Commander (build exists in the repo at v1.10.0 but not in the npm 1.7.0 release).
  • Local-first HTML — KaTeX fonts are inlined as base64 and Mermaid SVGs lose their Google Fonts import, so the page needs no CDN.
  • Live preview — render --watch serves on 127.0.0.1 and reloads over Server-Sent Events.
  • Presentation mode — ?present adds fragments, a grid overview, and a second-window presenter view with notes and a timer.
  • PDF and PNG export — landscape 16:9 pages with heading-derived bookmarks, or one PNG per slide, through a browser already installed.
  • Static build — build writes the same HTML to <name>-site/index.html, which opens from file://.

563 Vitest tests passed on the last CI run on main (2026-09-17) across Linux, macOS and Windows; the repo is tagged v1.10.0 but npm serves only 1.7.0, and the project has 0 stars and 39 npm downloads in the 30 days to 2026-10-18.

Architecture

A flat src/ of 21 TypeScript files (6,742 lines) compiles with plain tsc to dist/index.js, with no bundler, on Node 22 or newer. src/render.ts holds the pure, synchronous generateHtml(), which lexes the Markdown once and renders each hr-delimited group into its own <section>. Frontmatter uses a narrow hand-written key: value parser instead of a YAML dependency, falling back to whole-file-as-body so a deck opening with a bare --- is not misread.

The local-asset modules are small: katexAssets.ts inlines KaTeX fonts, mermaidRenderer.ts renders through beautiful-mermaid, and codeHighlight.ts registers 12 highlight.js grammars. server.ts is a plain node:http server on loopback, and watch mode uses Server-Sent Events. The presentation client is driven only by location.hash and location.search, which is why build output works off file://.

The repo is tagged v1.10.0 (2026-09-16), but npm has one version, 1.7.0, published the same day. 1.8.0 through 1.10.0 were never pushed and no workflow has a publish step. All twelve releases landed in five days, and the last non-Dependabot commit to main is dated 2026-09-17. CI covers three operating systems on Node 22 and latest, a two-Chromium pixel diff (its 2% tolerance has only ever seen 0.000%, so it is unproven as a detector) and an axe-core scan; main requires 8 status checks but no PR review.

How It Works

  1. Write deck.md: a --- after a blank line is a slide boundary, markers such as <!-- note --> and <!-- fragment --> apply per slide, and optional frontmatter sets theme:, dir: and transition:.
  2. Resolve options — --theme beats frontmatter theme:, and --css <path> beats both with a full stylesheet replacement; an unknown theme warns and falls back to light instead of failing.
  3. Generate HTML — generateHtml() lexes once and splits at hr tokens; mermaid fences go to beautiful-mermaid, math to KaTeX (fonts inlined only when math is present), other fences to highlight.js.
  4. Serve — startServer() binds 127.0.0.1 on an OS-assigned port and opens the browser unless --no-open; with --watch, a file change re-renders and reloads the page.
  5. Present — ?present switches to one slide at a time with keyboard, click and swipe navigation, fragment reveal, an o overview and a p presenter window.
  6. Export — pdf and png pick the first installed Chrome, Chromium, Edge or Brave, or exit non-zero with a message; puppeteer-core prints 16:9 pages with a heading-derived outline or crops one PNG per slide, and build writes the same HTML to deck-site/index.html.
  7. Gate — every PR runs typecheck, Biome and Vitest on six OS and Node combinations, the pixel diff and an axe-core scan; the repo still has 10 open code-scanning alerts (9 OpenSSF Scorecard findings and 1 CodeQL hit in a test file).