Skip to content
lesprgmPublic

About

A new way to browse the internet

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

258 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Roulette (Non-Deterministic Website)

Live Website: Roulette

Websites Generated Version

What Is This?

I was wondering if a website could change every time you visited it (I need new wonders). What if every person sees an entirely different website during each visit. Imagine interdimensional cable from Rick and Morty, but for websites.

Roulette is a generative UI system that uses large language models (LLMs) to create complete interactive web experiences at runtime. Users do not prompt to make websites. The fun part is that each click opens a random one-off interface, game, tool, storefront, simulator, dashboard, or tiny internet object that probably should not exist but somehow does.

Repeated LLM generations tend to cluster around familiar ideas, layouts, and interaction patterns. Roulette reduces this output homogenization by controlling diversity at the system level, composing each generation across dimensions such as format, task model, interaction loop, visual style, layout, and motion before the model builds the website. Structural fingerprints and recent-generation history then help prevent repeated experiences from reaching the user.

Each generation produces something weird, different, or unique (I don't know what you'll see, so I hope it's not too weird).

The system combines:

  • Combinatorial creative entropy to keep generations from feeling like the same template each time
  • Interaction model so each site has a role, first action, feedback loop, and reason to keep interacting. No boring generic websites
  • Burst queueing so one LLM request can produce multiple usable websites (I needed to get around rate limits somehow)
  • Iframe sandboxing so every generated world can run safely and reset cleanly

Screenshots

v2 Generated Websites

v1.5 Generated Website 4
Generated Website
v1.5 Generated Website 1
Generated Website
v1.5 Generated Website 2
Generated Website
v1.5 Generated Website 3
Generated Website

v1.5 Generated Websites

v1.5 Generated Website 4
Generated Website
v1.5 Generated Website 1
Generated Website
v1.5 Generated Website 2
Generated Website
v1.5 Generated Website 3
Generated Website

v1 Generated Websites

v1 Generated Website 1
Generated Website
v1 Generated Website 2
Generated Website
v1 Generated Website 3
Generated Website
v1 Generated Website 4
Generated Website

How It Works

graph TD
    A[User Clicks Generate] --> B[Frontend App]
    B --> C{Queue Has Page?}
    C -->|Available| D[Return Queued Result]
    C -->|Empty| E[Request Live Generation]
    E --> F[Generate Page<br/>format → task → flavor → LLM plan + build]
    F --> H{Primary Failed?}
    H -->|No| I[Normalize & Validate]
    H -->|Yes| H2[Fallback LLM Model]
    H2 --> I
    I --> Q[Visual + Task + Experience Checks]
    Q --> M{Check Deduplication}
    M -->|Unique| N[Render in Browser]
    M -->|Duplicate| E
    N --> O[Show Generated Experience]
    O --> R[Record Descriptor + Fingerprints]
    R --> P[Queue Top-Up]
    P --> C
    D --> N

    subgraph Queue Fill
    P1[Request Batch]
    P2[Streaming HTML Parser]
    P3[Enqueue Site #1]
    P4[Enqueue Remaining Approved Sites]
    P1 --> P2
    P2 -->|Site 1 Complete| P3
    P2 -->|More Sites Complete| P4
    end
    P ---> P1

    style A fill:#e1f5ff
    style O fill:#d4edda
    style H fill:#f8d7da
    style H2 fill:#e1f5ff
Loading

Combinatorial Creative Entropy

Roulette's novelty system is inspired by Shannon entropy, the information theory concept introduced by Claude Shannon in 1948 to describe uncertainty and surprise in a message.

Roulette applies that idea to creative generation, but the randomness is not flat. Each generation starts from a recognizable format such as a game, quiz, editor, booking flow, planner, dashboard, simulator, or mini app. Then the system gives that format a task model: user goal, domain objects, state variables, controls, and a completion condition. The backend composes a spatial graph from page regions and relationships, then assigns a compatible visual specification: exact palette roles, code-generated visual media, state-linked motion, and a format-specific copy budget.

Across the format, task, reward, visual-specification, palette, composition, renderer, and motion choices, Roulette has over 1,400 quadrillion possible generation targets. This is combinatorial creative entropy: novelty created through structured combinations, while the task model keeps the result recognizable instead of incoherent.

flowchart TD
 G["New Generation"] --> A["Concrete Format"]
 A --> B["Task Model"]
 B --> C["Interaction Loop"]
 C --> D["Visual Specification"]
 D --> E["Layout Model + Palette"]
 E --> F["Rendering + Motion"]
 F --> H["One Generated Website"]
Loading
flowchart LR
 A["Breakout Game"] --> Z["Task Model"]
 B["Paddle + Ball + Bricks"] --> Z
 C["Score + Lives + Restart"] --> Z
 Z --> V["Visual Specification"]
 D["Exact Palette + Composition"] --> V
 E["Renderer Stack + Motion"] --> V
 V --> W["Recognizable game, strange world"]
Loading

Architecture Components

Component Location Purpose
Frontend UI templates/index.html
static/ts-src/app.ts
static/ts-src/landing-controller.ts
static/ts-src/generated-site-host.ts
Landing tunnel, generation controls, and iframe sandbox renderer
NDW Runtime static/ts-src/ndw.ts Custom JavaScript runtime for games: loop(dt), input handling, canvas helpers, RNG
API Backend api/main.py
api/routes/
FastAPI application assembly and focused generation, metrics, and prefetch routers
Configuration api/settings.py Typed startup settings and validated environment defaults
LLM Client api/llm_client.py LLM planner, one-shot self-correcting raw-HTML build, fallback routing, and burst parsing
Prefetch Engine api/prefetch.py Shared queue, preview tokens, Redis/file storage, and lane isolation.
Deduplication api/dedupe.py Content fingerprinting to prevent near-identical outputs
Generation Models api/generation/ Task models, compositional layout models, visual specifications, prompt contracts, Redis diversity steering, and task/interaction scoring
Validators / Quality api/preflight.py
api/quality.py
Local asset/runtime preflight and visual scoring
Node.js Tooling package.json, static/ts-src/ Tailwind + TypeScript build pipeline for frontend assets

Quick Start

Prerequisites

  • Python 3.9+
  • Node.js 16+
  • An LLM API key for normal generation

Installation

  1. Clone the repository
git clone https://github.com/lesprgm/Roulette.git
cd Roulette
  1. Set up Python environment
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
  1. Install Node dependencies
npm install
  1. Configure API keys

Create a .env file in the project root:

GEMINI_API_KEY=your_gemini_api_key_here
  1. Build frontend assets
npm run build
  1. Start the server
uvicorn api.main:app --reload
  1. Open your browser

Navigate to http://localhost:8000 and click a preview or generate a new world.

Development Mode

For active development with auto-reloading:

# Terminal 1: Watch and rebuild TypeScript + CSS
npm run watch

# Terminal 2: Run FastAPI with hot reload
uvicorn api.main:app --reload

How to Use

  1. Visit the landing page at http://localhost:8000
  2. Click a tunnel preview to enter a queued random world instantly
  3. Use Generate inside the runtime to jump to another world

API Endpoints

Endpoint Method Description
/ GET Landing page with roulette tunnel previews
/generate POST Serve or generate a new experience
/generate/stream POST Streaming generation with progress updates
/metrics/total GET Count of sites actually served to users
/prefetch/status GET Check queue status and refill settings
/api/premium/previews GET Admin/dev inspection of the shared queue
/prefetch/fill POST Manually refill prefetch queue
/llm/status GET LLM provider configuration and status
/llm/probe GET Test LLM provider connectivity

Configuration

Configure behavior via environment variables:

LLM Provider Settings

Variable Description Default
GEMINI_GENERATION_MODEL Primary Gemini generation model gemini-3.5-flash
GEMINI_FALLBACK_MODEL Gemini fallback generation model gemini-3-flash-preview
GEMINI_THINKING_LEVEL Gemini thinking budget medium
GEMINI_MAX_OUTPUT_TOKENS Gemini generation output cap 64000
GEMINI_PREMIUM_BUILD_MAX_OUTPUT_TOKENS Build/burst output cap 64000
GEMINI_API_KEY Google AI Studio API key required for live generation
LLM_TIMEOUT_SECS Request timeout in seconds 105

The live provider and its fallback model are configured through these environment variables. Queueing and local gates provide the reliability layer around model calls.

Queue & Caching

Variable Description Default
DEDUPE_ENABLED Enable duplicate detection true
DEDUPE_RECENT_FILE Deduplication database file cache/seen_pages.json
PREMIUM_QUEUE_ENABLED Enable the shared queue lane true
PREMIUM_FILL_TO Target queue size after refill 10
PREMIUM_LOW_WATER Trigger top-up when queue drops 3
PREMIUM_BATCH_SIZE Number of candidates per live/top-up burst 10
PREMIUM_BURST_MIN_HTML_BYTES Reject tiny/minimal burst candidates before serving or queueing 3000
PREFLIGHT_HTML_WARN_BYTES Warn on unusually large generated pages 180000
PREFLIGHT_HTML_BLOCK_BYTES Block extreme generated pages before serving or queueing 280000
PREMIUM_TOKEN_TTL_SECONDS Preview token lifetime 900
PREMIUM_TOPUP_ENABLED Allow background queue refill false
STREAM_KEEPALIVE_SECONDS Keepalive ping interval while stream generation waits for the first page 8
PREFETCH_PREWARM_COUNT Number of docs to generate before startup 0
REDIS_DIVERSITY_ENABLED Store served-site descriptors, recent-choice counters, and fingerprints in Redis when REDIS_URL exists true
REDIS_COUNTER_KEY Durable Redis key used by the public served-site counter ndw:metrics:total
REDIS_COUNTER_TIMEOUT Redis counter connection/read timeout in seconds 2.0
COUNTER_BASELINE Optional one-time migration floor for an empty replacement database 0
FORMAT_CATALOG_PATH Combined private YAML generation catalog supplied as a Render Secret File /etc/secrets/variant_catalog.yaml
DIVERSITY_HTML_CACHE_TTL_SECONDS Optional TTL for cached generated HTML descriptors 604800
DIVERSITY_FINGERPRINT_TTL_SECONDS Short-term descriptor/structure fingerprint TTL 604800

The public product uses the shared queue. Background jobs may enqueue docs, but the public Sites generated metric only increments when a user is actually served a site. When the queue is empty, the backend starts one live streaming burst, serves the first locally valid page, and drains later valid pages from that same stream into the queue. Failed candidates and unattempted burst slots are discarded; the next queue miss naturally starts a new burst. By default, startup/top-up refill is disabled to avoid burning provider request quota in the background.

PREFETCH_* variables configure preview-token behavior, local file fallback, and the operator fill endpoint. They do not represent a separate public generation mode.

The catalog loader and schema stay versioned in Python. The proprietary YAML weights and formats are intentionally gitignored; production reads the combined catalog from the Render Secret File variant_catalog.yaml, while local development can use split files under data/.

Other Settings

Variable Description Default
ALLOW_OFFLINE_GENERATION Use stub generation (no LLM) for testing false
ALLOW_ORIGINS CORS allowed origins (comma-separated) *

Testing

Run the full test suite:

pytest

Run specific test categories:

# Test LLM generation and prompt engineering
pytest tests/generation/test_llm_generation.py

# Test frontend rendering
pytest tests/quality/test_snippet_render_dom.py

# Test prefetch system
pytest tests/storage/test_prefetch.py

# Test with coverage
pytest --cov=api --cov-report=html

# Generate a manual review pack
python3 scripts/run_generation_review_pack.py \
 --benchmark benchmarks/review_pack_v1.json \
 --modes \
 --out artifacts/evals

The test suite includes 170+ tests covering:

  • Prompt engineering and LLM response validation
  • NDW runtime behavior and safety checks
  • Schema normalization and validation
  • Deduplication logic
  • Prefetch queue management
  • API endpoint behavior
  • Frontend iframe rendering (full HTML and NDW snippets)
  • One-shot self-correction and local preflight validation

Deployment

Deploy to Render

This project includes a render.yaml blueprint for one-click deployment:

  1. Push to GitHub
git push origin main
  1. Create Render Service
  • Go to Render Dashboard
  • Click New > Blueprint
  • Connect your GitHub repository
  • Render will detect render.yaml automatically
  1. Configure Environment Variables

Add GEMINI_API_KEY and REDIS_URL in the Render dashboard. Other settings can use the defaults in render.yaml unless you are intentionally changing queue or model behavior.

  1. Deploy

Render will automatically:

  • Install Python dependencies
  • Install Node dependencies
  • Build frontend assets with npm run build
  • Start the server with Uvicorn
  • Auto-deploy on future pushes

Manual Deployment

For other platforms (Heroku, Railway, Fly.io, etc.):

  1. Build step:
pip install -r requirements.txt
npm install
npm run build
  1. Start command:
uvicorn api.main:app --host 0.0.0.0 --port $PORT

Project Goals & Design Principles

Why "Non-Deterministic"?

Traditional websites show the same content every time. This project explores the opposite: what if every visit generated something new? By leveraging AI, we create:

  • Infinite variety - No two generations are identical
  • Shared randomness - The app is roulette-first; it does not ask users to prompt a site into existence
  • Primary LLM queue - planner/builder generation is the default user-facing path
  • Interactive-first - generated worlds are coherent mini-experiences, not static landing pages
  • Creative surprise - Unexpected combinations and themes
  • Instant gratification - Prefetching makes it feel instantaneous

Key Technical Decisions

  1. Two Rendering Modes
  • Full HTML pages: Complete standalone experiences
  • NDW snippets: Lightweight canvas-based games/visuals using our custom runtime
  1. queue
  • The app serves from a shared queue first
  • If the queue is empty, one LLM streaming burst serves the first valid page and queues later valid pages
  • Background refill is disabled by default to avoid silently burning provider quota
  1. Deduplication System
  • Content fingerprinting prevents boring repetition
  • Recent generations are tracked and rejected if too similar
  • Ensures fresh, varied outputs
  1. Prompt Engineering
  • Planner prompts start from a concrete format and task model before style decisions
  • Concrete formats and task models determine behavior before visual direction is applied
  • Builder prompts receive stable runtime rules, local design-kit keys, and novelty guidance
  • Runtime constraints keep outputs renderable inside the NDW host
  • The configured fallback model is used only when primary generation fails
  1. Quality Guardrails
  • Raw HTML extraction avoids JSON escaping failures
  • One-shot self-review plus local preflight checks for safety and reliability
  • Experience scoring checks visible first action, meaningful state change, feedback clarity, mobile support, and decorative-only interaction risk
  • Runtime safety checks (canvas creation, error overlays)
  • Comprehensive test coverage

Development

New contributors should start with Contributor Onboarding for the module map, local setup, request traces, and debugging order.

Project Structure

Roulette/
├── api/          # FastAPI backend
│  ├── main.py      # Application assembly, middleware, and static hosting
│  ├── routes/      # Generation, prefetch, and metrics HTTP endpoints
│  ├── generation/premium_service.py # Premium queue and burst orchestration
│  ├── llm_client.py   # LLM planner/builder + burst parser
│  ├── prefetch.py    # Shared queue storage lanes
│  ├── settings.py    # Typed startup configuration
│  ├── dedupe.py     # Duplicate detection
│  └── validators.py   # Schema validation
├── static/
│  ├── ts-src/      # TypeScript source
│  │  ├── app.ts     # Initialization and event wiring
│  │  ├── generation-client.ts # HTTP and stream parsing
│  │  ├── generated-site-host.ts # Iframe lifecycle
│  │  ├── landing-controller.ts # Landing and tunnel state
│  │  └── ndw.ts     # NDW runtime
│  └── js/           # Generated JavaScript (build output)
├── templates/
│  └── index.html     # Landing page
├── tests/         # Test suite
├── screenshots/      # Demo images by version
│  ├── v1.5/       # Latest screenshots
│  └── v1/        # Original release screenshots
└── package.json      # Node dependencies

Code Style

This project uses:

  • Python: Black formatting, type hints preferred
  • TypeScript: ESLint + Prettier
  • Tests: pytest with extensive coverage

Format code before committing:

# Format Python
black api/ tests/

# Format TypeScript
npm run format

# Lint TypeScript
npm run lint

Node.js Build Pipeline

Node.js powers the asset build workflow. The scripts in package.json run Tailwind’s CLI (npm run build:css) and the TypeScript compiler (npm run build:ts) to produce static/tailwind.css and the ES modules in static/js/. During development you can run npm run watch to keep both pipelines hot. Once those assets exist, the FastAPI server serves them directly—no Node.js runtime is required in production.

Additional Resources

Contributing

Contributions welcome! Areas for improvement:

  • New prompt engineering techniques
  • Additional validation logic
  • NDW runtime features (WebGL, audio, etc.)
  • Metrics dashboard
  • Visual diff testing for generated pages
  • Better queue moderation/inspection UI

License

MIT License - see LICENSE file for details.


Built with by Leslie | Report Issues | View Source

About

A new way to browse the internet

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages