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

@tishlang/orbit

v0.1.3

Published

Hybrid (SSG / SSR / ISR) markdown-first web framework written in Tish. File-based routing, layouts, Tailwind, SEO, islands, Vercel Build Output.

Readme

@tishlang/orbit

A hybrid web framework written in Tish: file-based routing, markdown collections, JSX layouts, Tailwind-style utilities, SEO, client islands, and per-route static / server / incremental rendering with streaming. Builds to the Vercel Build Output API or a plain Node server.

npx @tishlang/orbit new my-site && cd my-site && npm install && npx orbit dev

Project layout

orbit.config.tish      site metadata, collections, redirects, tailwind theme
pages/                 routes: index.tish → /, blog/[slug].tish → /blog/:slug, docs/[...path].tish
pages/_layout.tish     nearest-directory layouts (nest freely)
pages/404.tish         not-found page
content/<collection>/  markdown with frontmatter
islands/               client-side modules (.js or .tish) mounted on demand
public/                copied verbatim
styles/*.css           your CSS, prepended to the generated utilities

Pages

import { raw, articleLd, formatDate } from '@tishlang/orbit'

export let render = 'isr'        // "static" (default) | "server" | "isr"
export let revalidate = 3600     // isr: seconds
export let stream = false        // server/isr: flush the shell, stream defer() boundaries

export fn paths(ctx) { return ctx.collections.blog.map(p => ({ params: { slug: p.slug } })) }
export async fn load(ctx) {
  let post = ctx.bySlug(ctx.collections.blog, ctx.params.slug)
  if (post === null) { return { notFound: true } }        // or { redirect: "/x", status: 301, headers: { … } }
  return { props: { post }, headers: { 'x-custom': '1' } }
}
export fn head(ctx, props) { return { title: props.post.title, description: props.post.excerpt, type: 'article', jsonLd: articleLd(ctx.site, props.post, props.post.url) } }
export fn page(ctx, props) { return <article>{raw(props.post.html)}</article> }

ctx carries site, path, params, query, headers, collections, dev, and helpers bySlug, byTag, paginate, allTags, allItems. Returning a string from page writes it verbatim (set export let contentType = "application/xml").

Layouts export layout(ctx, children, props) and optionally head(ctx, props); the page's head wins.

Streaming

export let render = 'server'
export let stream = true
export fn page(ctx) { return <div>{defer(slowPromise(), <p>Loading…</p>)}</div> }

The shell flushes immediately; each defer() resolves out-of-order and swaps in place.

Islands

{island('counter', { start: 3 }, { load: 'visible' })}     // idle (default) | visible | eager

islands/counter.js exports default function mount(el, props). Islands are separate ES modules (natural code splitting); .tish islands are compiled to JS. Only pages that use islands ship the loader.

Runtime (fs / fetch / env)

Site code never imports tish:* or node:* (they cannot run on the JS target). Use the host shim:

import { fetch, readFile, env } from '@tishlang/orbit'
export async fn load(ctx) { let r = await fetch('https://api.github.com/…', { headers: { authorization: 'bearer ' + env('GITHUB_TOKEN') } }); return { props: await r.json() } }

The same code runs natively under tish run (tests) and under Node/Vercel.

Config

export let site = {
  title, description, url, author, lang, twitter, image, icon, themeColor,
  titleTemplate: '%s · Site',
  feeds: { rss: '/rss.xml', atom: '/atom.xml', collections: ['blog'], limit: 30 },
  collections: { blog: { dir: 'content/blog', route: '/blog/:slug', sortBy: 'date', desc: true, drafts: false } },
  redirects: [{ from: '/old/*', to: '/new/*' }, { from: '/post/:id', to: '/blog/:id', status: 301 }],
  trailingSlash: true,                  // default: /blog → /blog/ (308); false: /blog/ → /blog
  tailwind: { theme: { colors: { brand: { '500': '#6366f1' } }, fonts: {}, screens: {} }, preflight: true },
  styles: ['styles/base.css'],
  head: ['<link rel="preconnect" …>'], bodyEnd: [],
  prefetch: true,                       // hover / viewport link prefetch
  sitemapExclude: ['/drafts/'], robots: ['Disallow: /admin'],
  functionIncludes: ['content']         // dirs copied into the server function
}

Generated automatically: sitemap.xml, robots.txt, RSS/Atom, canonical + Open Graph + Twitter + JSON-LD tags, hashed stylesheet.

Tailwind

Utilities are generated from the classes found in your pages, content, and islands: spacing scale, sizing, fractions, typography, the full Tailwind color palette with /alpha, borders, radius, shadows, grid, transforms, transitions, animations, and arbitrary values (w-[42px], bg-[#0ff]). Variants: sm…2xl, hover, focus, active, group-hover, dark, first/last/odd/even, motion-reduce, before/after, placeholder, [&>p]. Dynamic class names ("p-" + n) are not detected.

Build & deploy

| Command | Output | |---|---| | orbit dev | dev server with live reload (/_orbit/events SSE) | | orbit build --target vercel | .vercel/output/ (default when VERCEL=1): static pages, ISR prerender functions, one Node function for server routes | | orbit build --target node + orbit start | serves .orbit/static and runs server/ISR routes in-process with a TTL cache |

On Vercel: framework preset Other, build command npm run build, no output directory needed. The Tish compiler comes from the @tishlang/tish devDependency.

Tests

npm test           # unit tests (tish test test/)
npm run test:e2e   # scaffold the template, build for node and Vercel, serve, and check the responses

License

MIT