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

@metalbolicx/blueprint

v0.1.0

Published

Transactional code generator with Hygen-compatible templates

Readme

Blueprint

A fast, transactional template generator — a modern replacement for Hygen.

Generate code, config files, or any text from templates with atomic commits, declarative prompts, and no runtime dependencies. Language-agnostic — the same engine drives TypeScript, Go, Python, Rust, SQL, YAML, or any text output.

npx blueprint generate react-component --name User --path src/components

Installation

npm install -g blueprint

For non-installed use:

npx blueprint <command>

Onboarding

Scaffold a runnable hello-world template in your project:

blueprint init
blueprint generate hello-world myfirst

Produces hello-myfirst.md in the current directory.

For global installation (templates stored in ~/.config/blueprint/):

blueprint init --global
blueprint generate hello-world myfirst

Both commands are idempotent — re-running is safe and produces no changes.

Quick start

  1. Initblueprint init scaffolds .blueprint.yaml and a hello-world example in _templates/hello-world/
  2. Author — create a manifest + template files:
_templates/
└── component/
    └── new/
        ├── manifest.yaml
        └── files/
            └── Component.tsx.ejs.t
# manifest.yaml
name: component
classification: component
prompts:
  - name: name
    type: input
    description: "Component name (PascalCase)"
    default: MyComponent
  - name: path
    type: input
    description: "Output path"
    default: src/components
# files/Component.tsx.ejs.t
---
to: <%= path %>/<%= name %>.tsx
---
import React from 'react'

interface <%= name %>Props {
  children?: React.ReactNode
}

export const <%= name %>: React.FC<<%= name %>Props> = ({ children }) => {
  return <div className="<%= h.kebabCase(name) %>"><%= children %></div>
}
  1. Generateblueprint generate component --name Button --path src/ui

CLI usage

# Show help
blueprint --help

# Scaffold .blueprint.yaml
blueprint init

# Generate from a template classification
blueprint generate <classification> [options]

# Options:
#   --name <name>     Component name (PascalCase)
#   -n, --name <name> Short form
#   --force           Skip prompts, overwrite existing files
#   -f, --force       Short form
#   --output <dir>    Output directory
#   -o, --output <dir> Short form
#   --<key> <value>   Arbitrary attributes passed to templates
 
# Template registry management
# blueprint template copy <classification>      Copy a project generator into global registry
# blueprint template list                      List registry entries (name + source path)
# blueprint template remove <classification>   Remove a global template and its registry entry

Examples

# Basic generation with prompts
blueprint generate react-component

# With explicit name (skips name prompt)
blueprint generate react-component --name Button

# Force overwrite existing files
blueprint generate react-component --name Button --force

# Custom output directory
blueprint generate react-component --name Button --output src/ui

# Pass custom attributes
blueprint generate react-component --name Button --path src/components --framework react18

# Use short flags
blueprint generate react-component -n Button -f -o src/ui

Template format

manifest.yaml

Declares metadata, classification, and interactive prompts:

name: component
classification: component
prompts:
  - name: package
    type: input
    description: "Package or module name"
    default: main
  - name: framework
    type: select
    description: "Framework"
    options:
      - react
      - vue
      - svelte
  - name: includeTests
    type: confirm
    description: "Include test file?"
    default: true

Template files (*.ejs.t)

Frontmatter defines the operation; body is the template. Uses EJS syntax.

---
to: src/<%= name %>.tsx
inject: React.FC<<%= name %>Props>
---
import React from 'react'

interface <%= name %>Props {
  children?: React.ReactNode
}

export const <%= name %>: React.FC<<%= name %>Props> = ({ children }) => {
  return <div className="<%= h.kebabCase(name) %>"><%= children %></div>
}

Frontmatter directives

| Directive | Type | Description | |-----------|------|-------------| | to | string | Target file path | | inject | string | Regex pattern to match for replacement | | after | string | Regex — insert content after this pattern | | before | string | Regex — insert content before this pattern | | prepend | bool | Prepend content to existing file | | append | bool | Append content to existing file | | force | bool | Overwrite existing file | | sh | string | Shell command to execute after render |

Directive examples

to — Write to a specific path:

---
to: src/<%= name %>.tsx
---

inject — Replace content matching a regex:

---
inject: const \w+ = new
---
const newInstance = new Constructor()

after — Insert after a regex match:

---
after: class \w+
---
  // Added after class definition

before — Insert before a regex match:

---
before: export default
---
// Header comment

prepend — Add to the beginning of a file:

---
prepend: true
---
// This goes at the top

append — Add to the end of a file:

---
append: true
---
// This goes at the bottom

force — Overwrite without prompting:

---
to: src/<%= name %>.tsx
force: true
---

script — Run a configured script after render:

---
to: src/<%= name %>.tsx
script: setup
---

Context variables

Available inside every template via EJS:

| Variable | Description | |----------|-------------| | <%= name %> | Component name (lowercase) | | <%= Name %> | Component name (PascalCase) | | <%= names %> | Pluralized lowercase | | <%= Names %> | Pluralized PascalCase | | <%= path %> | User-provided path attribute | | <%= package %> | User-provided package attribute | | Any prompt answer | Available by its name |

FuncMaps (template helpers)

Available as h.* in templates:

| Function | Example | Result | |----------|---------|--------| | h.pascalCase(str) | <%= h.pascalCase("hello_world") %> | HelloWorld | | h.camelCase(str) | <%= h.camelCase("hello_world") %> | helloWorld | | h.kebabCase(str) | <%= h.kebabCase("HelloWorld") %> | hello-world | | h.snakeCase(str) | <%= h.snakeCase("HelloWorld") %> | hello_world | | h.upper(str) | <%= h.upper("hello") %> | HELLO | | h.lower(str) | <%= h.lower("HELLO") %> | hello | | h.trim(str) | <%= h.trim(" hello ") %> | hello | | h.title(str) | <%= h.title("hello world") %> | Hello World |

Hooks

Lifecycle hooks in .blueprint.yaml:

hooks:
  pre_generate: echo "Starting generation..."
  post_generate: prettier --write generated/
  timeout: 30s

Supported interpreters: bash, sh, node, python3, pwsh.

Safety

  • Transactional: renders to temp staging dir, commits atomically — no partial writes
  • Rollback: on any failure (render error, shell error), staged files are cleaned up
  • Conflict resolution: bulk prompt — [y]es to all, [n]o to all, [s]elect individually, [a]bort

Global template registry

  • Template registry entries are stored in ~/.config/blueprint/config.yaml under the registry array. Each entry records name, source (absolute path to the original project generator), and path (the installed ~/.config/blueprint/templates/<name>/ location).
  • blueprint template copy <classification> copies the entire source generator directory (manifest + actions) into the registry folder and persists the entry.
  • blueprint template list shows installed templates and their originating paths.
  • blueprint template remove <classification> deletes the registry directory and removes the associated config entry.
  • Discovery automatically appends registry paths after the project’s _templates/templates/generators stack, so local generators still win when a name conflicts.

Local release

Publish from a clean worktree to avoid shipping unintended files:

git stash                 # or git checkout -- .
pnpm build                # ReScript compile + rolldown bundle
pnpm res:test             # full test suite
npm pack --dry-run        # inspect the exact file list
npm publish --access public
git tag v<version>
git push --tags

Publishing

The package is published as @metalbolicx/blueprint (scoped).

Pre-publish checklist

git stash                 # or git checkout -- .
pnpm build                # ReScript compile + rolldown bundle
pnpm res:test             # full test suite — must be 675/675 green
npm pack --dry-run        # verify clean tarball (only LICENSE, README.md, dist/main.mjs, package.json)
npm publish --dry-run --access public

Run pnpm release:smoke for a single-command readiness check (build → pack → install → invoke → cleanup).

After publish

git tag v<version>
git push --tags

Note

The bin name stays "blueprint" even though the package is scoped — users run npx blueprint, not npx @metalbolicx/blueprint.

Docs

Full documentation at /docs, including architecture, API reference, and tutorials.