npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hacknock/lobster

v0.3.0

Published

Build web pages from Markdown only — extended parser with layout blocks, no build step, CSS-first

Readme

lobster.js

Extended Markdown parser for rich, structured web pages — works in the browser and Node.js.

Demo & Docs → · Showcase → · Try on StackBlitz →

lobster.js takes a Markdown file with its own extended syntax and turns a near-empty HTML page into a fully structured document — no build step, no framework. It provides document structure only; appearance is entirely up to CSS via predictable lbs-* class names.

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="your-style.css" />
    <!-- bring your own CSS -->
  </head>
  <body>
    <div id="content"></div>
    <script type="module">
      import { loadMarkdown } from "./lobster.js";
      loadMarkdown("./content.md", document.getElementById("content"));
    </script>
  </body>
</html>

lobster.js outputs semantic HTML with lbs-* class names. No stylesheet is bundled in the package — styling is entirely up to you. Ready-to-use CSS themes are provided in docs/themes/ for quick starts and inspiration.


Features

  • All standard Markdown — headings, paragraphs, bold, italic, strikethrough, code, blockquotes, lists, tables, links, images
  • Extended syntax unique to lobster.js:
    • :::header / :::footer — semantic page header and footer regions
    • :::details — native collapsible <details> / <summary> blocks
    • :::warp + [~id] — define content once, place it anywhere (great for multi-column layouts)
    • Silent tables (~ | … |) — borderless layout grids
    • Table cell merging — horizontal (\|) and vertical (\---) colspan/rowspan
    • Image sizing — ![alt](url =800x600)
    • Heading anchors — ## My Section {#my-section} adds an id attribute for deep linking
    • Footnotes — reference ([^id]) and inline (^[text])
  • CSS-first styling — all elements get lbs-* class names; bring your own stylesheet
  • Multi-file loading — pass an array of paths to loadMarkdown to merge multiple Markdown files into one page; all warp/link/footnote definitions are shared across files
  • Platform-agnostic coresrc/core/ has zero DOM/browser dependencies; portable to Node.js, Deno, and potentially native mobile
  • TypeScript — full type definitions included

Installation

npm / pnpm

npm install @hacknock/lobster
# or
pnpm add @hacknock/lobster
import { toHTML } from "@hacknock/lobster";
const html = toHTML("# Hello\n\nThis is **lobster**.");

CDN / local file

The latest build is available via GitHub Pages:

<script type="module">
  import { loadMarkdown } from "https://hacknock.github.io/lobsterjs/lobster.js";
  loadMarkdown("./content.md", document.getElementById("content"));
</script>

Or download lobster.js from the releases page and host it yourself.


API

toHTML(markdown: string): string

Convenience one-liner. Parses and renders Markdown to an HTML string.

import { toHTML } from "@hacknock/lobster";
const html = toHTML("# Hello");

parseDocument(markdown: string): Document

Parses Markdown into an AST. Useful for inspecting or transforming the document tree before rendering.

import { parseDocument } from "@hacknock/lobster";
const doc = parseDocument(markdown);
console.log(doc.body); // BlockNode[]

renderDocument(doc: Document): string

Converts a Document AST into an HTML string.

import { parseDocument, renderDocument } from "@hacknock/lobster";
const html = renderDocument(parseDocument(markdown));

loadMarkdown(src: string | string[], container?: HTMLElement): Promise<void>

Fetches one or more Markdown files and renders them into the given DOM element (defaults to document.body). Browser only.

When an array is passed, all files are fetched in parallel, concatenated with a blank line, and parsed as a single document — so warp/link/footnote definitions are shared across all files.

import { loadMarkdown } from "@hacknock/lobster";

// Single file
await loadMarkdown("./content.md", document.getElementById("content"));

// Multiple files — fetched in parallel, merged before parsing
await loadMarkdown(["./shared.md", "./content.md"], document.getElementById("content"));

Syntax overview

Standard Markdown works as you would expect. The sections below highlight lobster.js-specific extensions.

Page layout blocks

:::header
# My Site
:::

:::footer
© 2025 My Site
:::

Collapsible sections

:::details Click to expand
Hidden content goes here.
:::

Multi-column layout with Warp

~ |             left              |             right             |
~ | :---                          | :---                          |
~ | [~col-left]                   | [~col-right]                  |

:::warp col-left
Left column content
:::

:::warp col-right
Right column content
:::

Image sizing

![Logo](logo.png =200x)
![Banner](banner.jpg =1200x400)

Footnotes

Lobster[^1] is great. So is inline^[No definition needed] footnotes.

[^1]: A crustacean — or a Markdown parser.

Table cell merging

| A | B \|   |     ← B and the next cell merge horizontally
| \--- | C |       ← first cell merges with the one above

For the full syntax reference see markdowns/spec.md (English) or markdowns/spec-ja.md (日本語).


CSS classes

Every rendered element carries a lbs-* class name so any stylesheet can target it. For the complete HTML output reference, minimum viable stylesheet, dark mode tips, and an AI prompt template, see markdowns/styling.md.

Quick reference:

| Class | Element | | :--------------------------------------------------------- | :----------------------- | | lbs-heading-1lbs-heading-6 | Headings (<h1><h6>) | | lbs-paragraph | Paragraph | | lbs-emphasis / lbs-strong / lbs-strikethrough | Inline decorations | | lbs-code-span / lbs-code-block / lbs-code-filename | Code | | lbs-blockquote | Blockquote | | lbs-ul / lbs-ol / lbs-list-item / lbs-checkbox | Lists | | lbs-table / lbs-table-silent | Tables | | lbs-header / lbs-footer | Page regions | | lbs-details / lbs-summary | Collapsible | | lbs-footnote-ref / lbs-footnotes / lbs-footnote-item | Footnotes |


Themes

The repository ships several ready-to-use stylesheets you can copy and adapt:

| File | Style | | :------------------------------------------------------- | :------------------------------------------------ | | docs/style.css | Default — clean, minimal, light | | docs/themes/pop.css | Pop — bright, rounded, playful (coral/pink) | | docs/themes/pastel.css | Pastel — soft, dreamy, gentle (lavender/mint) | | docs/themes/formal.css | Formal — strict, professional, serif (navy) | | docs/themes/engineer.css | Engineer — dark, terminal-like, dev-tool feel |

You can switch between them on the demo page using the theme selector in the page header.


Syntax highlighting

lobster.js has no built-in highlighter, but fenced code blocks with a language tag emit a language-* class on the <code> element — the convention used by Prism.js, highlight.js, and most other highlighters.

```js
console.log("hello");
```

Rendered output:

<div class="lbs-code-block">
  <pre data-language="js"><code class="language-js">console.log(&quot;hello&quot;);</code></pre>
</div>

Prism.js

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs/themes/prism.min.css" />
<script src="https://cdn.jsdelivr.net/npm/prismjs/prism.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/plugins/autoloader/prism-autoloader.min.js"></script>
import { loadMarkdown } from "./lobster.js";
loadMarkdown("./content.md", document.getElementById("content")).then(() => Prism.highlightAll());

highlight.js

import { loadMarkdown } from "./lobster.js";
import hljs from "highlight.js";
loadMarkdown("./content.md", document.getElementById("content")).then(() => hljs.highlightAll());

Diagrams with Mermaid

lobster.js renders fenced ```mermaid blocks as <code class="language-mermaid">. After loadMarkdown() resolves, replace those elements with Mermaid's expected <div class="mermaid"> and call mermaid.run().

```mermaid
flowchart LR
  A[Plan] --> B[Delay] --> C[Cancel] --> D[Apologize] --> A
```
<script type="module">
  import { loadMarkdown } from "https://hacknock.github.io/lobsterjs/lobster.js";
  import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";

  mermaid.initialize({ startOnLoad: false });

  await loadMarkdown("./content.md", document.getElementById("content"));

  document.querySelectorAll("code.language-mermaid").forEach((code) => {
    const wrapper = code.closest(".lbs-code-block");
    const div = document.createElement("div");
    div.className = "mermaid";
    div.textContent = code.textContent;
    (wrapper ?? code).replaceWith(div);
  });

  await mermaid.run();
</script>

Claude Code skills

If you use Claude Code, two skills are available for lobster.js:

| Skill | What it does | | :------------- | :-------------------------------------------------------------------------------------------------------------- | | lobster-init | Scaffolds index.html + content.md. Describe the page to generate real content, or omit for a bare skeleton. | | lobster-css | Generates a CSS stylesheet targeting lbs-* class names. Describe the design you want. |

Installation

Download lobster-init.skill and lobster-css.skill from the latest release and install them:

# Global install — available in every Claude Code session
unzip lobster-init.skill -d ~/.claude/skills/lobster-init
unzip lobster-css.skill  -d ~/.claude/skills/lobster-css

Once installed, Claude will use the skills automatically when you ask to create or style a lobster.js page, or invoke them explicitly as /lobster-init and /lobster-css.


Development

Requirements

| Tool | Version | | :---------------------------- | :--------- | | mise | 2026.2.19+ | | pnpm | 10.30.1 | | Node.js | 24.13.1 |

Setup

# Install mise
brew install mise
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc

# Install pnpm and Node.js (versions defined in mise.toml)
mise install

# Install dependencies
pnpm install

Commands

pnpm test          # Run tests (Vitest)
pnpm test:watch    # Watch mode
pnpm build         # Bundle to dist/
pnpm build:docs    # Copy bundle to docs/ for GitHub Pages

Project structure

src/
├── core/                # Platform-agnostic parser (no DOM dependency)
│   ├── types.ts         # All AST type definitions
│   ├── block-parser.ts  # Block-level parser
│   ├── inline-parser.ts # Inline-level parser
│   └── index.ts
├── renderer/html/
│   ├── renderer.ts      # AST → HTML string
│   └── dom.ts           # DOM helpers (browser only)
├── index.ts             # Browser entry point (full API)
└── index.node.ts        # Node.js entry point (pure functions only)

tests/                   # Vitest test suites
markdowns/               # Specification documents
docs/                    # GitHub Pages demo site

Contributing

Issues and pull requests are welcome.

  1. Fork the repository
  2. Create a feature branch: git checkout -b feat/my-feature
  3. Add tests for any new behaviour
  4. Run pnpm test and make sure all tests pass
  5. Open a pull request

License

MIT © 2022 Hacknock