# Proa Playground

Interactive demo of Proa's compile-time SSR engine. Renders full Airbnb and Nike
pages in single-digit microseconds — with a side-by-side comparison against React
SSR on Node.js and Bun.

## Quick start

```bash
./run.sh
# Opens http://localhost:3001
```

On Windows, double-click `run.bat` or run it from a terminal.

## What's inside

```
proa-playground          Proa SSR engine (standalone binary, no runtime needed)
run.sh / run.bat         Launch script — checks deps, installs JS packages, starts server
ffi/
  libproa_demo.dylib     FFI shared library (.so on Linux, .dll on Windows)
  proa.h                 C header for calling render functions from any language
public/                  Images, fonts, CSS, and JS assets for the showcase pages
hono-ssr/                Hono server for React SSR comparison (Node.js / Bun)
react-ssr-shared/        React components (same pages, used by the Hono server)
showcase-props.json      Default JSON props for all showcase pages
```

## Engines

The playground runs three SSR engines for comparison:

| Engine | Runtime | How it works |
|--------|---------|-------------|
| **Proa** | None (native binary) | Templates compiled to byte sequences at build time. No interpreter, no GC. |
| **React (Node)** | Node.js >= 20 | React `renderToString()` served by Hono on `@hono/node-server`. |
| **React (Bun)** | Bun >= 1.0 | Same React/Hono code, but served via `Bun.serve()` for native HTTP I/O. |

Proa always works. The React engines are optional — if Node or Bun aren't installed,
the playground still runs with just the Proa engine.

## Dependencies

**Required:** None. The Proa binary is fully self-contained.

**Optional (for React comparison):**
- **Node.js >= 20** — needed for the `--import` flag used to load TypeScript via `tsx`
- **Bun >= 1.0** — uses `Bun.serve()` natively (not `@hono/node-server`)
- **npm or pnpm** — `run.sh` auto-installs JS dependencies on first launch

## FFI

The `ffi/` directory contains a shared library you can call from Python, Ruby, Go,
C, or any language with C FFI support:

```python
import ctypes

lib = ctypes.CDLL("./ffi/libproa_demo.dylib")  # .so on Linux

lib.render_airbnb_home.restype = ctypes.c_int32
lib.render_airbnb_home.argtypes = [
    ctypes.POINTER(ctypes.POINTER(ctypes.c_uint8)),
    ctypes.POINTER(ctypes.c_size_t),
]
lib.proa_free.restype = None
lib.proa_free.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t]

ptr = ctypes.POINTER(ctypes.c_uint8)()
length = ctypes.c_size_t(0)
lib.render_airbnb_home(ctypes.byref(ptr), ctypes.byref(length))

html = ctypes.string_at(ptr, length.value).decode("utf-8")
lib.proa_free(ptr, length)
print(f"{len(html):,} bytes")  # 162,746 bytes
```

Available functions: `render_airbnb_home`, `render_airbnb_search`,
`render_airbnb_listing`, `render_nike_catalog`, `render_nike_pdp`,
plus `_json` variants that accept custom props and `_into` variants
for zero-allocation buffer reuse. See `ffi/proa.h` for the full API.

## Showcase pages

| Page | Engine | URL |
|------|--------|-----|
| Airbnb Home | Proa | http://localhost:3001/showcase/airbnb/proa |
| Airbnb Home | Node | http://localhost:3001/showcase/airbnb/node |
| Airbnb Home | Bun | http://localhost:3001/showcase/airbnb/bun |
| Airbnb Search | Proa | http://localhost:3001/showcase/airbnb/proa/search |
| Airbnb Listing | Proa | http://localhost:3001/showcase/airbnb/proa/listing |
| Nike Catalog | Proa | http://localhost:3001/showcase/nike/proa |
| Nike Product | Proa | http://localhost:3001/showcase/nike/proa/product |

The playground UI at http://localhost:3001/playground lets you edit props,
switch engines, and run load tests.

## Architecture

The Proa binary is an Axum HTTP server that:

1. Serves the playground UI (embedded HTML/CSS/JS)
2. Renders Proa showcase pages via compiled templates (microseconds)
3. Proxies `/showcase/*/node` requests to the Hono server on port 3100
4. Proxies `/showcase/*/bun` requests to the Hono server on port 3200
5. Rewrites links in proxied HTML so navigation stays within the same engine
6. Serves static assets (images, fonts) from the `public/` directory

The Hono server is spawned as a child process by the binary. If Node/Bun
aren't available, those routes return 502 and the Proa engine works standalone.

## License

Copyright (c) 2026 The Proa Authors. All rights reserved. See LICENSE for details.
