The framework that fits in your head.
b0nes is a complete web development toolkit with zero dependencies. Build modern websites with components, routing, state management, and progressive enhancementβall in pure JavaScript.
// Everything you need, nothing you don't
β
Components (atoms β molecules β organisms)
β
Server-Side Rendering (SSR)
β
Static Site Generation (SSG)
β
State Management (built-in Store)
β
State Machines (built-in FSM + SPA Router)
β
Client-side Interactivity
β
Zero npm dependencies# Traditional setup:
npx create-react-app my-app # 847 packages, 412 MB
npm install redux react-router # More dependencies...
npm run build # 500KB+ JavaScript bundle
# Junior dev: "I just wanted to build a website..." π°# b0nes setup:
git clone b0nes.git # 0 packages, <1 MB
cd b0nes
node src/framework/index.js # Start building immediately
# Junior dev: "This makes sense!" πLearn the entire framework in an afternoon. Use it for years.
- π§© Atomic Design System - Well-organized component hierarchy (atoms β molecules β organisms)
- π― Pure JavaScript - No TypeScript, no frameworks, no build tools required
- π¦ Zero Dependencies - Runs on Node.js built-ins only
- π SSR & SSG - Built-in server-side rendering and static site generation
- π State Management - Redux-style store without the complexity
- π€ State Machines - XState-style FSM for flow control AND SPA routing
- β¨ Progressive Enhancement - Works without JavaScript, better with it
- π§ͺ Auto-Testing - Built-in test discovery and runner
- π¨ CSS-Agnostic - Use Tailwind, vanilla CSS, or any framework you want
- π Interactive Components - Tabs, modals, dropdowns with zero dependencies
- π¦ Component Installer - Install community components from URLs
- Node.js v20+ installed
- A terminal
- That's it!
git clone https://github.com/iggydotdev/b0nes.git
cd b0nes
ls src/components/atoms # Explore available componentsnpm run dev:watchOpen http://localhost:5000 - You'll see a working site! π
npm run generate atom badgeThis creates:
src/components/atoms/badge/
βββ index.js
βββ badge.js
βββ badge.test.js
Edit src/components/atoms/badge/badge.js:
import { processSlotTrusted } from '../../utils/processSlot.js';
import { normalizeClasses } from '../../utils/normalizeClasses.js';
export const badge = ({ slot, variant = 'default', className = '', attrs = '' }) => {
attrs = attrs ? ` ${attrs}` : '';
const classes = normalizeClasses(['badge', `badge-${variant}`, className]);
const slotContent = processSlotTrusted(slot);
return `<span class="${classes}"${attrs}>${slotContent}</span>`;
};Edit src/framework/pages/home.js:
export const components = [
{
type: 'organism',
name: 'hero',
props: {
slot: [
{
type: 'atom',
name: 'text',
props: { is: 'h1', slot: 'Welcome to b0nes' }
},
{
type: 'atom',
name: 'badge',
props: { slot: 'New!', variant: 'primary' }
}
]
}
}
];Refresh http://localhost:5000 - See your changes live! β¨
npm run buildYour static site is ready in public/:
public/
βββ index.html
βββ demo/
β βββ index.html
βββ blog/
βββ [postid]/
βββ index.html
# Serve locally
npx serve public
# Or deploy to:
# - Netlify (drag & drop public/ folder)
# - Vercel (vercel --prod)
# - GitHub Pages
# - Any static host!- β Built a component-based site
- β Zero npm dependencies installed
- β No build tools configured
- β Pure JavaScript + HTML
- β Production-ready output
- β Ready to deploy
Atoms (15 basic elements):
accordion- Collapsible contentbadge- Status indicators/labelsbox- Flexible container (div, section, article, etc.)button- Clickable buttondivider- Horizontal ruleimage- Image elementinput- Form inputlink- Anchor elementpicture- Responsive imagessource- Media source elementtext- Any text element (p, h1-h6, span, etc.)textarea- Multi-line inputvideo- Video element
Molecules (4 compound components):
card- Content card with header/media/content slotstabs- Interactive tabbed interface β‘modal- Overlay dialog β‘dropdown- Click-to-toggle menu β‘
Organisms (4 page sections):
header- Page/section headerfooter- Page/section footerhero- Hero sectioncta- Call-to-action section
β‘ = Requires b0nes.js for client-side interactivity
// Direct usage
import { button } from './components/atoms/button/button.js';
const html = button({
type: 'submit',
slot: 'Click Me',
className: 'primary large'
});// In page composition
{
type: 'organism',
name: 'hero',
props: {
slot: [
{
type: 'atom',
name: 'text',
props: { is: 'h1', slot: 'Welcome' }
},
{
type: 'atom',
name: 'button',
props: { slot: 'Get Started' }
}
]
}
}Generate new components with proper structure:
# Create an atom
npm run generate atom my-button
# Create a molecule
npm run generate molecule my-card
# Create an organism
npm run generate organism my-headerInstall community components from URLs:
# Install from URL
npm run install-component https://example.com/components/my-card
# Preview without installing
npm run install-component https://example.com/card --dry-run
# Force overwrite existing
npm run install-component https://example.com/card --forceComponent Manifest Format:
{
"name": "my-card",
"version": "1.0.0",
"type": "molecule",
"description": "A custom card component",
"author": "Your Name <[email protected]>",
"license": "MIT",
"files": {
"component": "./my-card.js",
"test": "./my-card.test.js",
"client": "./molecule.my-card.client.js"
},
"dependencies": [],
"tags": ["card", "layout"]
}b0nes includes a zero-dependency client-side runtime for progressive enhancement.
Keyboard-accessible tabbed interface with arrow key navigation:
{
type: 'molecule',
name: 'tabs',
props: {
tabs: [
{ label: 'Overview', content: 'Overview content...' },
{ label: 'Features', content: 'Feature 1' },
{ label: 'Docs', content: 'Documentation...' }
]
}
}Features:
- Click to switch tabs
- Arrow keys for navigation
- ARIA-compliant markup
- Works without JS (shows all content)
Accessible overlay dialog with focus management:
// 1. Define the modal
{
type: 'molecule',
name: 'modal',
props: {
id: 'welcome-modal',
title: 'Welcome!',
slot: 'Thanks for visiting our site!'
}
}
// 2. Add a trigger button
{
type: 'atom',
name: 'button',
props: {
attrs: 'data-modal-open="welcome-modal"',
slot: 'Show Welcome Message'
}
}Features:
- Click overlay or X to close
- Escape key to close
- Focus trap when open
- Body scroll lock
- ARIA-compliant
Click-to-toggle menu with outside-click detection:
{
type: 'molecule',
name: 'dropdown',
props: {
trigger: 'Actions βΎ',
slot: [
{
type: 'atom',
name: 'link',
props: { url: '#edit', slot: 'Edit' }
},
{
type: 'atom',
name: 'link',
props: { url: '#delete', slot: 'Delete' }
}
]
}
}Features:
- Click to toggle
- Outside click to close
- Escape key to close
- ARIA-compliant
Server renders HTML with data-b0nes attributes
β
Client loads /b0nes.js runtime (optional)
β
Runtime discovers components
β
Attaches interactive behaviors
β
Progressive enhancement complete!
Disable interactivity for specific pages:
// In routes.js
meta: {
title: 'Static Page',
interactive: false // Don't load b0nes.js
}b0nes includes a Redux-style store without the complexity:
import { createStore } from './framework/client/store.js';
const store = createStore({
state: {
count: 0,
todos: []
},
actions: {
increment: (state) => ({
count: state.count + 1
}),
addTodo: (state, todo) => ({
todos: [...state.todos, todo]
})
},
getters: {
todoCount: (state) => state.todos.length
}
});
// Usage
store.dispatch('increment');
store.dispatch('addTodo', { id: 1, text: 'Learn b0nes' });
console.log(store.getState()); // { count: 1, todos: [...] }
console.log(store.computed('todoCount')); // 1
// Subscribe to changes
const unsubscribe = store.subscribe((change) => {
console.log('State changed:', change);
console.log('New state:', change.state);
});Organize large applications with modules:
import { combineModules, createModule } from './framework/client/store.js';
const userModule = createModule({
state: { name: '', email: '' },
actions: {
login: (state, userData) => ({ ...userData })
}
});
const cartModule = createModule({
state: { items: [] },
actions: {
addItem: (state, item) => ({
items: [...state.items, item]
})
}
});
const store = createStore(
combineModules({
user: userModule,
cart: cartModule
})
);
// Namespaced access
store.dispatch('user/login', { name: 'John', email: '[email protected]' });
store.dispatch('cart/addItem', { id: 1, name: 'Product' });Add cross-cutting concerns:
import {
loggerMiddleware,
persistenceMiddleware
} from './framework/client/store.js';
const store = createStore({
state: { cart: [] },
actions: { /* ... */ },
middleware: [
loggerMiddleware, // Logs all state changes
persistenceMiddleware('cart') // Auto-saves to localStorage
]
});b0nes includes XState-style finite state machines for flow control AND SPA routing. It's functional, uses closures for private state, and is perfect for authentication, multi-step forms, UI flows, and single-page apps.
Perfect for authentication, multi-step forms, and UI flows:
import { createFSM } from './framework/client/fsm.js';
const authFSM = createFSM({
initial: 'logged-out',
states: {
'logged-out': {
on: { LOGIN: 'logging-in' }
},
'logging-in': {
actions: {
onEntry: (context, data) => {
console.log('Starting login...');
// Return context updates if needed
return { loading: true };
},
onExit: (context, data) => {
console.log('Exiting login...');
}
},
on: {
SUCCESS: 'logged-in',
FAILURE: 'logged-out'
}
},
'logged-in': {
on: { LOGOUT: 'logged-out' }
}
},
context: { user: null } // Initial context
});
// Usage
authFSM.send('LOGIN', { username: 'grok' }); // Transition with data
authFSM.getState(); // 'logging-in'
authFSM.is('logged-in'); // false
authFSM.can('LOGOUT'); // false
authFSM.getContext(); // { user: null, loading: true }
authFSM.getHistory(); // Array of transitions
authFSM.updateContext({ user: 'grok' }); // Update without transition
authFSM.reset(); // Back to initial
// Subscribe to changes
const unsubscribe = authFSM.subscribe((transition) => {
console.log('Transition:', transition); // { from, to, event, data, timestamp }
});
// Visualize
console.log(authFSM.toMermaid()); // Mermaid diagram stringTransitions can be functions for dynamic targets:
const checkoutFSM = createFSM({
initial: 'cart',
states: {
'cart': {
on: {
CHECKOUT: (context, data) => context.items.length > 0 ? 'payment' : 'cart'
}
},
'payment': {
on: { SUCCESS: 'complete' }
},
'complete': {}
},
context: { items: [] }
});Run multiple FSMs together:
import { composeFSM } from './framework/client/fsm.js';
const composed = composeFSM({
auth: authFSM,
checkout: checkoutFSM
});
composed.getAllStates(); // { auth: 'logged-out', checkout: 'cart' }
composed.getAllContexts(); // Combined contexts
composed.send('auth', 'LOGIN'); // Send to specific machine
composed.broadcast('RESET'); // Send to all that can handle it
// Subscribe to any transition
composed.subscribe((change) => {
console.log(change); // { machine: 'auth', from, to, ... }
});For routing, use createRouterFSM to generate an FSM from routes, then connectFSMtoDOM to wire it to the UI. This handles rendering templates, updating URLs, browser history, and event delegation.
import { createRouterFSM, connectFSMtoDOM } from './framework/client/fsm.js';
const routes = [
{
name: 'start',
url: '/demo/fsm/start',
template: "<h1>FSM Demo</h1><button data-fsm-event='GOTO_STEP2'>Next</button>",
onEnter: (context, data) => console.log('Entered start')
},
{
name: 'step2',
url: '/demo/fsm/step2',
template: "<h1>Step 2</h1><button data-fsm-event='GOTO_START'>Back</button>"
},
{
name: 'success',
url: '/demo/fsm/success',
template: "<h1>Success!</h1>"
}
];
const { fsm, routes: fsmRoutes } = createRouterFSM(routes); // Creates FSM with GOTO_ events
// Connect to DOM (handles render, clicks, popstate)
const rootEl = document.querySelector('[data-bones-fsm]');
const cleanup = connectFSMtoDOM(fsm, rootEl, routes);
// Navigate programmatically
fsm.send('GOTO_STEP2');
// Cleanup when done
cleanup();- Routes get auto-connected with GOTO_[NAME] events.
- Use data-fsm-event on buttons/links for transitions.
- onEnter/onExit become state actions.
- Handles browser back/forward via popstate.
- Initial state matches current URL if possible.
const routes = [
{
name: 'start',
url: '/form/start',
template: "<h1>Start</h1><button data-fsm-event='GOTO_STEP2'>Next</button>"
},
{
name: 'step2',
url: '/form/step2',
template: "<h1>Step 2</h1><button data-fsm-event='GOTO_START'>Back</button><button data-fsm-event='GOTO_SUCCESS'>Submit</button>"
},
{
name: 'success',
url: '/form/success',
template: "<h1>Success!</h1><button data-fsm-event='GOTO_START'>Reset</button>"
}
];
const { fsm } = createRouterFSM(routes);
connectFSMtoDOM(fsm, document.getElementById('app'), routes);
**Why FSM?**
- β
Impossible states become impossible
- β
All transitions are explicit
- β
Easy to visualize and test
- β
Self-documenting code
- β
Prevents bugs from invalid state combinations
- β
Built-in SPA routing with FSM Router
---
## Routing & Pages
### Static Routes (SSG/SSR)
```javascript
// src/framework/routes.js
import { URLPattern } from './utils/urlPattern.js';
import { components as homeComponents } from './pages/home.js';
export const routes = [
{
name: 'Home',
pattern: new URLPattern({ pathname: '/' }),
meta: { title: 'Home' },
components: homeComponents
},
{
name: 'About',
pattern: new URLPattern({ pathname: '/about' }),
meta: { title: 'About Us' },
components: aboutComponents
}
];
{
name: 'Blog Post',
pattern: new URLPattern({ pathname: '/blog/:slug' }),
meta: { title: 'Blog Post' },
components: (data) => [
{
type: 'organism',
name: 'hero',
props: {
slot: [
{
type: 'atom',
name: 'text',
props: { is: 'h1', slot: data.title }
}
]
}
}
],
externalData: async () => {
// Fetch blog post data
const response = await fetch('https://api.example.com/posts');
return await response.json();
}
}// src/framework/pages/home.js
export const components = [
{
type: 'organism',
name: 'header',
props: {
slot: [
{ type: 'atom', name: 'link', props: { url: '/examples/home', slot: 'Home' } },
{ type: 'atom', name: 'link', props: { url: '/about', slot: 'About' } }
]
}
},
{
type: 'organism',
name: 'hero',
props: {
slot: [
{ type: 'atom', name: 'text', props: { is: 'h1', slot: 'Welcome' } },
{ type: 'atom', name: 'button', props: { slot: 'Get Started' } }
]
}
},
{
type: 'organism',
name: 'footer',
props: {
slot: [
{ type: 'atom', name: 'text', props: { is: 'p', slot: 'Β© 2025' } }
]
}
}
];Tests use simple assertion pattern:
// src/components/atoms/button/button.test.js
import button from './index.js';
export const test = () => {
const actual = button({
type: 'submit',
slot: 'Click Me',
className: 'primary'
});
const expected = '<button type="submit" class="btn primary">Click Me</button>';
return actual === expected
? true
: console.error({actual, expected}) || false;
};Run all tests:
npm run testOutput:
π¦ Testing atoms:
testing file: button.test.js
β PASS
testing file: link.test.js
β PASS
Test Summary: 23/23 passed
b0nes is CSS-agnostic by design. You choose how to style your components.
- β No forced design opinions
- β No CSS specificity conflicts
- β No breaking changes on updates
- β Works with any CSS strategy
- β Smaller bundle size
npm install -D tailwindcss
npx tailwindcss init// Use Tailwind classes in components
button({
slot: 'Click Me',
className: 'bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded'
})/* public/styles.css */
.btn {
padding: 0.5rem 1rem;
border-radius: 0.25rem;
border: none;
cursor: pointer;
}
.btn-primary {
background: #3b82f6;
color: white;
}import { stylesheetPresets } from './framework/renderPage.js';
// Tailwind CSS
meta: { stylesheets: stylesheetPresets.tailwind() }
// Water.css (classless)
meta: { stylesheets: stylesheetPresets.water('dark') }
// Pico CSS
meta: { stylesheets: stylesheetPresets.pico() }
// Open Props
meta: { stylesheets: stylesheetPresets.openProps() }
// Combine multiple
meta: {
stylesheets: stylesheetPresets.combine(
stylesheetPresets.water('auto'),
'/styles/custom.css'
)
}// src/framework/pages/landing.js
export const components = [
{
type: 'organism',
name: 'header',
props: {
className: 'sticky-header',
slot: [
{ type: 'atom', name: 'link', props: { url: '/examples/home', slot: 'Home' }},
{ type: 'atom', name: 'link', props: { url: '/pricing', slot: 'Pricing' }},
{ type: 'atom', name: 'link', props: { url: '/docs', slot: 'Docs' }}
]
}
},
{
type: 'organism',
name: 'hero',
props: {
className: 'hero-gradient',
slot: [
{ type: 'atom', name: 'text', props: { is: 'h1', slot: 'Ship Faster' }},
{ type: 'atom', name: 'text', props: { is: 'p', slot: 'Zero deps. Pure JS. Simple.' }},
{ type: 'atom', name: 'button', props: { slot: 'Get Started', className: 'cta-button' }}
]
}
},
{
type: 'atom',
name: 'box',
props: {
is: 'section',
className: 'features',
slot: [
{
type: 'molecule',
name: 'card',
props: {
headerSlot: 'Zero Dependencies',
contentSlot: 'Never breaks, always works'
}
},
{
type: 'molecule',
name: 'card',
props: {
headerSlot: 'Complete Toolkit',
contentSlot: 'Everything you need included'
}
}
]
}
},
{
type: 'organism',
name: 'cta',
props: {
slot: [
{ type: 'atom', name: 'text', props: { is: 'h2', slot: 'Ready to build?' }},
{ type: 'atom', name: 'button', props: { slot: 'Start Now' }}
]
}
},
{
type: 'organism',
name: 'footer',
props: {
slot: { type: 'atom', name: 'text', props: { is: 'p', slot: 'Β© 2025 Your Company' }}
}
}
];b0nes/
βββ src/
β βββ components/ # Component Library
β β βββ atoms/ # Basic elements (15 components)
β β βββ molecules/ # Compound components (4 components)
β β βββ organisms/ # Page sections (4 components)
β β βββ utils/ # Component utilities
β β βββ generator/ # Component generator
β β βββ tester.js # Test runner
β β βββ processSlot.js # Slot processing
β β βββ normalizeClasses.js
β β βββ componentError.js
β βββ framework/ # Framework Core
β βββ client/ # Client-side runtime
β β βββ b0nes.js # Component initialization
β β βββ store.js # State management
β β βββ fsm.js # State machines + SPA routing
β βββ pages/ # Page templates
β βββ utils/build/ # Build tools
β βββ compose.js # Component composition
β βββ router.js # URL routing
β βββ routes.js # Route definitions
β βββ renderPage.js # HTML generation
β βββ server.js # Dev server
βββ package.json
βββ README.md
βββ LICENSE
Recursively composes component tree into HTML.
import { compose } from './framework/compose.js';
const html = compose([
{ type: 'atom', name: 'text', props: { is: 'p', slot: 'Hello' } }
]);Wraps composed HTML in full page template.
import { renderPage } from './framework/renderPage.js';
const html = renderPage(content, {
title: 'My Page',
interactive: true, // Include b0nes.js (default: true)
stylesheets: ['/styles/main.css']
});Matches URL to route and returns route info.
import { router } from './framework/router.js';
const route = router(new URL('http://localhost/'), routes);
// Returns: { params, query, meta, components, ... }npm run buildOutputs to public/:
public/
βββ index.html
βββ demo/
β βββ index.html
βββ blog/
βββ post-1/
βββ index.html
- Build your site:
npm run build - Drag & drop the
public/folder to Netlify - Done!
npm run build
vercel --prodnpm run build
git subtree push --prefix public origin gh-pages- β‘ Fast builds - ~100ms for small sites
- β‘ No transpilation - Pure JavaScript
- β‘ No bundling - Direct HTML output
- β‘ Zero hydration - Server-rendered HTML
- β‘ Minimal JavaScript - Only for interactive components
- β‘ Progressive enhancement - Works without JS
- π’ Performance: 100
- π’ Accessibility: 100
- π’ Best Practices: 100
- π’ SEO: 100
| Feature | b0nes | Next.js | Astro | 11ty |
|---|---|---|---|---|
| Dependencies | 0 | 847+ | 320+ | 180+ |
| Learning Curve | 1 day | 2 weeks | 1 week | 3 days |
| State Management | β Built-in | β BYO | β BYO | β BYO |
| State Machines | β Built-in | β BYO | β BYO | β BYO |
| SPA Router | β FSM-based | β Built-in | β BYO | β BYO |
| Build Tool | β Not required | β Required | β Required | |
| Client JS | Progressive | Required | Optional | Optional |
| TypeScript | Optional | Built-in | Built-in | Optional |
- TypeScript declaration files (.d.ts)
- More interactive components (carousel, accordion with animation)
- Improved documentation with maybe video tutorials
- Component marketplace/registry
- Plugin system
- Middleware support for routing
- View Transitions API integration
- Component playground (Storybook-like)
- Hot module replacement (HMR)
and more to come!
Stability. Code that depends on nothing never breaks from dependency updates.
Simplicity. No version conflicts, no security vulnerabilities from dependencies, no maintenance overhead.
Longevity. This code will run 10 years from now without changes.
Accessibility. Everyone can read and understand the code, from juniors to AI.
Portability. No compilation step, no toolchain lock-in, runs anywhere Node.js runs.
Simplicity. What you see is what runs. No hidden transformations.
Standards. HTML has been around for 30+ years and will be around for 30+ more.
Performance. Server-rendered HTML is the fastest way to deliver content.
Accessibility. Semantic HTML is naturally accessible.
Predictability. All possible states and transitions are explicit.
Debugging. State machines are easy to visualize and test.
Safety. We can infer valid states and events.
Flexibility. FSM works for SPAs, multi-step forms, game states, and more.
Contributions are welcome! Please ensure:
- All tests pass:
npm run test - New components follow atomic design patterns
- JSDoc comments are included
- Zero dependencies maintained
- Follow existing code style
Areas we'd love help with:
- More interactive components (carousel, date picker, etc.)
- FSM visualization tools
- Performance optimizations
- Documentation improvements
- Example projects and tutorials
- Some tests need improvement (will use node:test in future)
- Component generator has template replacement issues (being addressed)
- Dynamic route generation needs more robust error handling
- FSM Router needs more examples and documentation
We're aware of these and they'll be addressed in upcoming releases.
b0nes is for different use cases:
- Use React/Next.js for: Complex SPAs, real-time apps, large teams
- Use b0nes for: Content sites, landing pages, docs, blogs, simple SPAs
Yes! While b0nes is written in pure JS, you can:
- Use JSDoc for type hints (no compilation needed)
- Add your own TypeScript layer on top
- We're working on official .d.ts files for v0.3.0
FSM Router:
- β Explicit state transitions
- β Built-in state management
- β Works with or without URLs
- β Perfect for multi-step flows
- β More verbose for simple routing
React Router:
- β Simpler for basic routing
- β Larger ecosystem
- β Implicit state transitions
- β Requires separate state management
Absolutely! Use the FSM Router:
const routes = [
{ name: 'home', url: '/examples/home', template: '<h1>Home</h1>' },
{ name: 'about', url: '/about', template: '<h1>About</h1>' }
];
const { fsm } = createRouterFSM(routes);
connectFSMtoDOM(fsm, document.getElementById('app'), routes);For static sites: Yes! (v0.2.0+)
- Zero dependencies = rock solid
- SSG output is just HTML/CSS/JS
For SPAs: Getting there! (v0.2.0)
- FSM Router is new but tested
- Use for new projects, not mission-critical apps yet
- We're working toward v1.0.0 for production SPAs
// Multi-step form with FSM
const routes = [
{ name: 'step1', url: '/step1', template: '<input id="name" /><button data-fsm-event="GOTO_STEP2">Next</button>' }
];
const { fsm } = createRouterFSM(routes);
connectFSMtoDOM(fsm, app, routes);// In route definition
{
name: 'Blog Post',
pattern: new URLPattern({ pathname: '/blog/:slug' }),
components: blogPostComponents,
externalData: async (params) => {
const res = await fetch(`https://api.example.com/posts/${params.slug}`);
return await res.json();
}
}Yes! b0nes is CSS-agnostic:
npm install -D tailwindcss
npx tailwindcss initOr use the built-in preset:
import { stylesheetPresets } from './framework/renderPage.js';
meta: {
stylesheets: stylesheetPresets.tailwind()
}MIT License - See LICENSE file
Copyright (c) 2025 Ignacio Garcia Villanueva
This is an attempt to do something different. Not to replace anything, but to propose another way.
We've been overengineering solutions for too long. It's time to question our choices and ask: "Is this really worth it?"
b0nes is for developers who:
- Want to understand how their framework works
- Value simplicity over complexity
- Prefer explicit over implicit
- Care about longevity and stability
- Don't want to rewrite their app every 2 years
If you think this is useful, let me know.
If you learn something from this, let me know.
Let's build something useful together.
Many thanks!
β Iggy
- π GitHub: https://github.com/iggydotdev/b0nes
- π¦ npm: https://www.npmjs.com/package/b0nes
- π Issues: https://github.com/iggydotdev/b0nes/issues
- π¬ Discussions: https://github.com/iggydotdev/b0nes/discussions
- π§ Email: [email protected]
- π¦ Twitter: @iggydotdev
β Star this repo if you find it useful!
π€ Contributions welcome! Check out our Contributing Guide
π’ Share your b0nes projects! We'd love to see what you build.