This website was made using futuristic internet technologies.
+ <= Back
+
+)
+```
+
+The default layout automatically includes `src/css/main.css` and `src/client/main.ts`, wraps your page content in ``, `
`, and `...`.
+
+### Accessing the request
+
+Page components receive `c` (the Hono context) and `req` (the Hono request) as props:
+
+```tsx
+// src/pages/greet.tsx
+export default ({ req }) => (
+
+
Hello, {req.query('name') ?? 'stranger'}!
+
+)
+```
+
+Visit `/greet?name=Chris` to see `Hello, Chris!`.
+
+For the full Hono context:
+
+```tsx
+// src/pages/debug.tsx
+export default ({ c, req }) => {
+ const ua = req.header('user-agent')
+ return (
+
+
Request Info
+
URL: {req.url}
+
User-Agent: {ua}
+
+ )
+}
+```
+
+---
+
+## SPA Apps
+
+For a single-page app with client-side rendering, disable the default layout and provide your own HTML shell:
+
+```ts
+// src/server/index.ts
+import { Hype } from '@because/hype'
+
+const app = new Hype({ layout: false })
+
+export default app.defaults
+```
+
+```tsx
+// src/pages/index.tsx
+export default () => (
+
+
+ My SPA
+
+
+
+
+
+
+
+
+
+
+)
+```
+
+```tsx
+// src/client/app.tsx
+import { render } from 'hono/jsx/dom'
+import { useState } from 'hono/jsx/dom'
+
+function App() {
+ const [count, setCount] = useState(0)
+
+ return (
+ <>
+
My SPA
+
Count: {count}
+
+
+ >
+ )
+}
+
+render(, document.getElementById('root')!)
+```
+
+The client-side app uses `hono/jsx/dom` for React-like rendering with hooks (`useState`, `useEffect`, etc.). Hype automatically transpiles and bundles `src/client/app.tsx` when the browser requests `/client/app.js`.
+
+### Cache-busting in SPAs
+
+Use the git hash to bust asset caches:
+
+```tsx
+// src/pages/index.tsx
+import { $ } from 'bun'
+
+const GIT_HASH = await $`git rev-parse --short HEAD`.text().then(s => s.trim()).catch(() => 'dev')
+
+export default () => (
+
+
+
+
+
+
+
+
+
+)
+```
+
+### Passing server data to the client
+
+Inject globals via an inline script:
+
+```tsx
+
+```
+
+---
+
+## Routing
+
+Hype supports two routing layers that work together.
+
+### File-based routing
+
+Files in `src/pages/` are automatically mapped to GET routes:
+
+| File | URL |
+|------|-----|
+| `src/pages/index.tsx` | `/` |
+| `src/pages/about.tsx` | `/about` |
+| `src/pages/contact.tsx` | `/contact` |
+
+Files prefixed with `_` are private and won't be served (returns 404). This is used for layouts and other internal files.
+
+### Custom routes
+
+Since Hype extends Hono, you can define any route directly:
+
+```ts
+// src/server/index.ts
+import { Hype } from '@because/hype'
+
+const app = new Hype()
+
+// JSON API
+app.get('/api/users/:id', (c) => {
+ return c.json({ id: c.req.param('id'), name: 'Chris' })
+})
+
+// Form handling
+app.post('/api/contact', async (c) => {
+ const body = await c.req.parseBody()
+ console.log('Message:', body.message)
+ return c.redirect('/thanks')
+})
+
+// Custom HTML
+app.get('/custom', (c) => {
+ return c.html('
Custom page
')
+})
+
+export default app.defaults
+```
+
+Custom routes are defined before the file-based routes, so they take priority.
+
+---
+
+## Layouts
+
+### Default layout
+
+By default, Hype wraps every page in a simple HTML5 layout that includes:
+
+- ``
+- `` for responsive design
+- `` for automatic dark mode
+- `` to `/css/main.css` (your `src/css/main.css`)
+- `
+
+
+
+ {children}
+
+
+
+)
+
+export default Layout
+```
+
+The layout receives:
+- `children` — the rendered page content
+- `title` — page title (defaults to `'hype'`)
+- `props` — the `HypeProps` passed to the constructor (useful for conditional CSS)
+
+### No layout
+
+Disable the layout entirely for full control (used in SPA mode):
+
+```ts
+const app = new Hype({ layout: false })
+```
+
+---
+
+## Pages
+
+Pages are `.tsx` files in `src/pages/` that export a default function (or raw JSX).
+
+### Function export (recommended)
+
+```tsx
+// src/pages/index.tsx
+export default ({ c, req }) => (
+
+
+
+)
+```
+
+### Async data in pages
+
+Since pages render on the server, you can use top-level await:
+
+```tsx
+// src/pages/users.tsx
+const users = await fetch('https://api.example.com/users').then(r => r.json())
+
+export default () => (
+
+
Users
+
+ {users.map(u =>
{u.name}
)}
+
+
+)
+```
+
+Note: top-level data is fetched once at import time and cached. For per-request data, use the `c` context:
+
+```tsx
+// src/pages/profile.tsx
+export default async ({ c, req }) => {
+ const userId = req.query('id')
+ const user = await fetch(`https://api.example.com/users/${userId}`).then(r => r.json())
+
+ return (
+
+
{user.name}
+
+ )
+}
+```
+
+### Private pages
+
+Prefix a file with `_` to prevent it from being served:
+
+```
+src/pages/_layout.tsx # not a route — used as the layout
+src/pages/_helpers.tsx # not a route — internal helpers
+src/pages/index.tsx # GET /
+```
+
+---
+
+## Client-Side JavaScript
+
+### Automatic transpilation
+
+TypeScript files in `src/client/` and `src/shared/` are automatically transpiled and bundled by Bun when requested by the browser. The URL maps directly to the file path:
+
+| File | URL |
+|------|-----|
+| `src/client/main.ts` | `/client/main.ts` |
+| `src/client/app.tsx` | `/client/app.js` |
+| `src/shared/utils.ts` | `/shared/utils.ts` |
+
+You can request `.ts` or `.js` extensions — Hype resolves `.ts` and `.tsx` files automatically.
+
+### Module imports
+
+Client-side files can import from each other using relative paths:
+
+```ts
+// src/client/main.ts
+import { initBurger } from './burger'
+
+initBurger()
+```
+
+```ts
+// src/client/burger.ts
+export function initBurger() {
+ document.addEventListener('click', (ev) => {
+ const el = (ev?.target as HTMLElement).closest('.burger') as HTMLImageElement
+ if (!el) return
+ el.src = '/img/bite.png'
+ })
+}
+```
+
+Imports are bundled — the full dependency graph is included in the output, so the browser only needs one request.
+
+### The default layout auto-includes `main.ts`
+
+When using the default layout, `src/client/main.ts` is automatically loaded as a module. Just create the file and it works.
+
+---
+
+## Styling
+
+### External CSS
+
+Put your styles in `src/css/main.css`. The default layout auto-includes it:
+
+```css
+/* src/css/main.css */
+section {
+ max-width: 500px;
+ margin: 0 auto;
+}
+```
+
+You can also serve additional CSS files from `src/css/`:
+
+```html
+
+```
+
+### Pico CSS
+
+Enable the bundled [Pico CSS](https://picocss.com) for classless styling:
+
+```ts
+const app = new Hype({ pico: true })
+```
+
+Or include it in a custom layout:
+
+```html
+
+```
+
+### CSS Reset
+
+Enable the bundled CSS reset (Josh W. Comeau's reset):
+
+```ts
+const app = new Hype({ reset: true })
+```
+
+Or include it in a custom layout:
+
+```html
+
+```
+
+### Combining options
+
+```ts
+const app = new Hype({ pico: true, reset: true })
+```
+
+### Inline CSS
+
+Use the `css` template tag for scoped inline styles in any page:
+
+```tsx
+import { css } from '@because/hype'
+
+export default () => (
+
+ {css`
+ .hero {
+ background: linear-gradient(135deg, #667eea, #764ba2);
+ color: white;
+ padding: 4rem 2rem;
+ text-align: center;
+ }
+ `}
+