8000 GitHub - kumavis/vibe-dump · GitHub
[go: up one dir, main page]

Skip to content
kumavisPublic

About

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

vibe-dump

A monorepo of tiny static web apps. Each lives in its own package, builds to plain HTML/CSS/JS with Vite, and shows up automatically in a gallery that's deployed to GitHub Pages.

🔗 Live gallery: https://kumavis.github.io/vibe-dump/

Layout

vibe-dump/
├─ packages/
│  ├─ origami-crane/    # each package is an independent static app (Vite + three)
│  └─ mirror-field/     # self-contained Three.js scene (no build step needed)
├─ dist/                # the assembled gallery — BUILT BY HAND AND COMMITTED
├─ scripts/
│  ├─ build-gallery.mjs # collects the apps + emits the grid index (no browser)
│  ├─ thumbnails.mjs    # shoots packages/<name>/thumbnail.jpg (run by hand)
│  ├─ verify.mjs        # checks dist/ matches packages/ — what CI runs
│  ├─ apps.mjs          # package discovery + metadata shared by the above
│  ├─ static-server.mjs # dependency-free static server (preview + screenshots)
│  ├─ serve.mjs
│  └─ clean.mjs
├─ vite.config.shared.js
└─ .github/workflows/   # ci.yml (verify) · deploy.yml (publish dist/)

How it works

  1. npm run build:apps builds every package (npm workspaces) into packages/<name>/dist.
  2. npm run build:gallery copies each app into dist/<name>/ along with its committed thumbnail.jpg, and writes a gallery dist/index.html — a tight grid of thumbnail + title + description, each card linking to the app. Cards are ordered newest vibe first and carry tags (game · simulation · tool · art · kids · tutorial), a wip/done status and the model that built them. The grid filters on tags and status — chips are OR within a group and AND across them, and the choice lives in the URL, so /vibe-dump/#art,wip is a shareable filtered view.
  3. You commit dist/. The workflow publishes it verbatim.

Two things are generated by hand and committed rather than rebuilt on every deploy, because both got more expensive with every vibe added:

  • dist/ — the whole assembled gallery. CI publishes the committed copy, so a deploy is a file copy with no Node, no npm and no build.
  • packages/<name>/thumbnail.jpg — captured with Playwright by npm run thumbnails. No build ever launches a browser, and a ca 9D62 rd only changes when someone deliberately re-shoots it.

Vite output is content-hashed and deterministic, so rebuilding an app you didn't touch produces byte-identical files — a PR's dist/ diff only covers what actually changed.

Apps use base: './' (see vite.config.shared.js) so they work under any sub-path — locally, in a file:// preview, or at /vibe-dump/<app>/ on Pages.

Commands

npm install              # install Vite + Playwright (run once)

npm run dev -w @vibe-dump/<slug>  # hot-reload a single app while building it
npm run build            # build all apps + gallery into dist/ (no browser needed)
npm run preview          # serve dist/ locally at http://127.0.0.1:4173
npm run verify           # check dist/ is in step with packages/ (what CI runs)
npm run clean            # delete dist/ and packages/*/dist — rebuild to restore

# thumbnails — only when adding a vibe or deliberately re-shooting one:
npx playwright install chromium   # one-time: fetch the screenshot browser
npm run thumbnails                # shoot any app with no thumbnail.jpg yet
npm run thumbnails -- <slug>...   # re-shoot specific apps
npm run thumbnails -- --all       # re-shoot every app
npm run thumbnails -- --check     # list apps missing one (exit 1)

Working on a vibe

Creating one

Pick a slug (kebab-case, e.g. particle-pond). It becomes both the directory name and the URL path (/vibe-dump/<slug>/).

  1. packages/<slug>/package.json — the gallery field is the card, so write a real title and a one-line pitch:

    {
      "name": "@vibe-dump/<slug>",
      "version": "0.0.0",
      "private": true,
      "type": "module",
      "scripts": { "dev": "vite", "build": "vite build" },
      "gallery": {
        "title": "Particle Pond",
        "description": "One-line pitch shown on the gallery card.",
        "tags": ["art"],
        "status": "wip",
        "models": ["Opus 5"],
        "thinking": "high"
      }
    }
    field values
    tags one or more of game, simulation, tool, art, kids, tutorial
    status done, or wip for a badge on the card
    models which model(s) built it, e.g. ["Opus 5"]
    thinking low / medium / high / extra / max / ultracode, or unknown

    The vocabularies live in scripts/apps.mjs, and npm run verify fails on a value outside them — a tag with no chip would drop the app out of every filtered view.

  2. packages/<slug>/vite.config.js — always re-export the shared config (it sets base: './' so the app works under the Pages sub-path):

    export { default } from '../../vite.config.shared.js'
  3. packages/<slug>/index.html plus whatever main.js / style.css it needs. Reference assets with relative paths (./main.js) — never absolute (/main.js).

  4. npm install once, so npm links the new workspace.

Then go round the iterate loop below until it's what you want.

Iterating on one

npm run dev -w @vibe-dump/<slug>    # hot reload while you work

The dev server is the fast loop. When the app is close, check it the way the gallery will see it — built, not hot-reloaded:

npm run build && npm run preview    # then open http://127.0.0.1:4173

Shooting its thumbnail

The card image is the app's whole pitch on the grid, and it isn't generated for you — a new vibe has no card until you shoot one, and npm run verify fails without it.

npm run build                       # thumbnails are shot against dist/, not dev
npm run thumbnails                  # only apps that don't have one yet

Look at the result (packages/<slug>/thumbnail.jpg) before moving on. If it came out blank, mistimed, or buried under the app's own chrome, tune it from the gallery.thumbnail field rather than accepting it:

"thumbnail": { "waitFor": "!#loading", "click": "#close-panel", "settle": 2000 }
  • waitFor — a selector to wait for before shooting; prefix ! to wait for it to leave (how space-goblin waits out its 20-second boot).
  • click — a control to press once the app is ready, for an app whose opening chrome hides its own subject (how rule-explorer collapses its detail rail and abyssal-* dismiss their intro modals).
  • settle — milliseconds to wait before the shot. Defaults to 1200.

Re-shoot with npm run thumbnails -- <slug> until it looks right. See CLAUDE.md for the full list of thumbnail gotchas.

Preparing the PR

Because dist/ is committed, the last step before pushing is always the same:

npm run build            # rebuild apps + gallery
npm run verify           # same check CI runs
git add packages/<slug> dist

Commit packages/<slug>/thumbnail.jpg along with the source — it's an input to the build, not output of it. Keep package-lock.json changes in their own commit, separate from anything touching app code.

CI on the PR runs npm run verify and nothing else: it builds nothing, installs nothing, and launches no browser. It only catches the one mistake this model makes possible — changing an app and forgetting to rebuild dist/ before committing. If it fails, the message names the app and the fix is always npm run build.

Deployment

.github/workflows/deploy.yml publishes the committed dist/ to GitHub Pages on every push to main, or manually via Actions → Deploy gallery to GitHub Pages → Run workflow. It runs no build — whatever is in dist/ on main is what goes live.

First-time setup: in Settings → Pages, set Source to GitHub Actions.

About

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0