Skip to content

Latest commit

Β 

History

History
72 lines (51 loc) Β· 2.55 KB

File metadata and controls

72 lines (51 loc) Β· 2.55 KB

πŸ„ Spore

Build fast. Ship lean.

A full-stack web microframework β€” five tools, zero bloat.

Quick Start

bunx degit TekkadanPlays/spore my-app
cd my-app && bun install
bun run build && bun run dev

Open http://localhost:3000.

The Stack

Layer Tool Why
Runtime Bun Fastest JS runtime. Bundles, serves, installs β€” in milliseconds.
Server Hono Ultra-fast routing, middleware, and static files in 14KB.
UI InfernoJS Fastest virtual DOM. React-compatible API at a fraction of the size.
Components Blazecn 49 shadcn/ui-compatible components β€” no React, no Radix.
State Preact Signals Fine-grained reactivity. No providers, no selectors β€” just .value.
Styling Tailwind CSS v4 OKLCH color system, utility-first, compiles in 56ms.

Project Structure

src/
β”œβ”€β”€ server.ts         Hono server β€” routes, APIs, static files
β”œβ”€β”€ template.ts       HTML shell with theme-flash prevention
β”œβ”€β”€ signals.ts        Reactive state layer (Preact Signals)
β”œβ”€β”€ styles.css        Tailwind v4 + design tokens (light/dark)
└── client/
    β”œβ”€β”€ entry.ts      Client entry β€” mounts Inferno
    └── App.ts        Your application

Scripts

Command What it does
bun run dev Start server with file-watch restart
bun run dev:css Watch and rebuild CSS on file changes
bun run build Build CSS + client bundle for production
bun run start Start production server

How It Works

Server β€” Hono serves an HTML shell at GET * and JSON APIs at /api/*. Static assets from public/.

Client β€” Bun bundles src/client/entry.ts into a single JS file. InfernoJS mounts your app. Blazecn provides the design system.

State β€” Preact Signals live outside the component tree. A SignalBridge component subscribes via effect() and triggers surgical Inferno re-renders:

import { signal, computed } from '@preact/signals-core';

const count = signal(0);
const doubled = computed(() => count.value * 2);

// Only re-renders this subtree when count changes:
S(() => createElement('span', null, count.value))

Theming β€” Light and dark mode via OKLCH design tokens in styles.css. The ThemeToggle component from Blazecn handles persistence.

License

MIT