# AI Agent Instructions for TS-Games

This document provides guidelines for AI agents working with the TS-Games project.

## Project Overview

TS-Games is a custom framework/build system for creating simple single-file TypeScript games. All games compile into one standalone HTML file with no external dependencies—all assets are inlined as data URLs.

## Key Concepts

### Two Types of Applications

1. **Games** - Interactive applications with game loops
   - Located in `src/games/<name>/`
   - Entry point: `index.ts` or `index.tsx`
   - Default export: `runGame()` function
   - Use `gameLoop()` from `@common/game` for structured game development

2. **Apps** - More complex applications (like AI-Story)
   - Also located in `src/games/<name>/`
   - Entry point: `index.tsx`
   - Default export: `main()` function
   - May use Preact components and complex state management

### Single HTML File Architecture

- All games build into a single `.html` file in `dist/`
- No external dependencies at runtime
- All assets (images, audio, fonts, WASM) are inlined as base64 data URLs
- Build process uses Bun's plugin system to transform assets

## Creating a New Game

### Step 1: Create Directory Structure

```bash
mkdir -p src/games/<yourgame>/assets
```

### Step 2: Create Entry Point

Create `src/games/<yourgame>/index.ts` or `index.tsx`:

```typescript
// Simple game example (index.ts)
import { gameLoop } from "@common/game";
import Input from "@common/input";

const setup = () => {
    // Initialize game state
    return { x: 0, y: 0 };
};

const frame = (dt: number, state: ReturnType<typeof setup>) => {
    // Update game state
    state.x += Input.getHorizontal() * dt;
    state.y += Input.getVertical() * dt;
};

export default gameLoop(setup, frame);
```

```tsx
// Preact component example (index.tsx)
import { render } from "preact";
import App from "./components/app";

export default function main() {
    render(<App />, document.body);
}
```

### Step 3: Add Assets (Optional)

Place assets in `src/games/<yourgame>/assets/`:

- **Images**: `.png`, `.jpg`, `.jpeg` → Import as `HTMLImageElement`
- **Audio**: `.wav`, `.mp3`, `.ogg` → Import as `HTMLAudioElement`
- **CSS**: `.css`, `.module.css` → Import as styles
- **Fonts**: `.font.css` → Import font faces
- **WASM**: `.c`, `.cpp`, `.wasm` → Import as WASM module
- **Icons**: `favicon.ico` → Auto-used as page icon
- **PWA**: `pwa_icon.png` → Used for PWA manifest

### Step 4: Import Assets

```typescript
// Import image
import spritesheet from './assets/spritesheet.png';
console.log(spritesheet); // <img src="data:image/png;base64,..." />

// Import audio
import heal from './assets/heal.ogg';
heal.play();

// Import CSS
import './assets/styles.css';

// Import CSS modules
import styles from './assets/styles.module.css';
<div className={styles.root} />

// Import WASM (C/C++)
import wasmModule from './assets/game.c';
// Access exports: wasmModule.memory, wasmModule.functionName()

// Import GLSL shader
import shader from './assets/shader.glsl';
```

## Development Workflow

### Running Development Server

```bash
bun start
```

Navigate to `http://localhost:3000` to see the game list. Games rebuild on each page reload.

To run a specific game:
```bash
bun start --game=<yourgame>
```

### Building for Production

Build a specific game:
```bash
bun run build <yourgame>
```

Or select from interactive list:
```bash
bun run build
```

Output: `dist/<yourgame>.html`

### Building with Options

- `--local`: Build for local testing (no PWA, different index)
- `--production`: Minify JS/CSS/HTML (default for build)

## Project Structure

```
tsgames/
├── src/
│   ├── games/           # All games/apps live here
│   │   ├── <game1>/     # Individual game directory
│   │   │   ├── index.ts # Entry point (required)
│   │   │   └── assets/  # Game assets
│   │   └── index/       # Special: game list page
│   ├── common/          # Shared utilities
│   │   ├── game.ts      # Game loop helper
│   │   ├── input.ts     # Input handling
│   │   ├── dom.ts       # DOM utilities
│   │   ├── utils.ts     # General utilities
│   │   ├── errors.ts    # Error formatting
│   │   ├── components/  # Shared Preact components
│   │   ├── hooks/       # React-like hooks
│   │   ├── display/     # Canvas/graphics utilities
│   │   └── physics/     # Physics utilities
│   └── types.d.ts       # Global type definitions
├── build/
│   ├── build.ts         # Build script
│   ├── server.ts        # Dev server
│   ├── html.ts          # HTML generation
│   ├── isGame.ts        # Game detection
│   ├── imagePlugin.ts   # Image bundler plugin
│   ├── audioPlugin.ts   # Audio bundler plugin
│   ├── fontPlugin.ts    # Font bundler plugin
│   ├── wasmPlugin.ts    # WASM bundler plugin
│   └── filePlugin.ts    # Generic file plugin
├── dist/                # Built HTML files
└── test/                # Tests
```

## Technical Details

### Bun Configuration

- Use `bun` for all package management and script running
- `.env` files are automatically loaded (no dotenv needed)
- Use `Bun.serve()` for servers (not express)
- Use `Bun.file()` for file operations (not fs)
- Use `Bun.$` for shell commands (not execa)

### TypeScript Configuration

- JSX: `react-jsx` with Preact
- Module resolution: `bundler`
- Path aliases: `@common/*` → `./src/common/*`
- Strict mode enabled

### Asset Processing

All asset processing happens at build time via Bun plugins:

1. **Images** (`.png`, `.jpg`, `.jpeg`):
   - Converted to base64 data URLs
   - Return `HTMLImageElement` that's ready to use

2. **Audio** (`.wav`, `.mp3`, `.ogg`):
   - Converted to base64 data URLs
   - Return `HTMLAudioElement` with loaded source

3. **CSS**:
   - Bundled and inlined in `<style>` tag
   - CSS modules supported (`.module.css`)
   - Modern CSS features transpiled (nesting, vendor prefixes)

4. **Fonts**:
   - Import via `.font.css` files
   - Base64 inlined

5. **WASM**:
   - `.c`/`.cpp`: Compiled to WASM at build time (requires clang)
   - `.wasm`: Direct inclusion
   - All inlined as base64 data URLs

### WASM Development

For C/C++ files:

```c
// Example: src/games/life/life.c
void EXPORT(init, void);
void EXPORT(frme, void);
int EXPORT(getCell, int x, int y);

// Must export memory
```

Requirements:
- Install: `sudo apt install clang lld wabt`
- Only function exports and `memory` supported

### PWA Support

Production builds include PWA manifest with:
- App name from game directory name (capitalized)
- Icon from `favicon.ico` or `pwa_icon.png`
- Fullscreen display mode

### Publishing

Configure `.env`:
```bash
PUBLISH_LOCATION=ssh.example.com:/var/www/games/
PUBLISH_URL=https://example.com/
```

Build and publish:
```bash
bun run build <yourgame>
```

## Common Patterns

### Game Loop Pattern

```typescript
import { gameLoop } from "@common/game";
import Input from "@common/input";

interface State {
    playerX: number;
    playerY: number;
    score: number;
}

const setup = (): State => {
    return {
        playerX: 100,
        playerY: 100,
        score: 0,
    };
};

const frame = (dt: number, state: State): State => {
    // Update based on input
    state.playerX += Input.getHorizontal() * 200 * dt;
    state.playerY += Input.getVertical() * 200 * dt;

    // Update score
    state.score += dt;

    // Return new state (optional)
    return state;
};

export default gameLoop(setup, frame);
```

### Preact Component Pattern

```jsx
import { useState, useEffect } from "preact/hooks";
import clsx from "clsx";
import styles from './app.module.css';

export function App() {
    const [count, setCount] = useState(0);
    const isActive = true;

    return (
        <div className={clsx(styles.container, {
            [styles.active]: isActive,
        })}>
            <h1>Count: {count}</h1>
            <button onClick={() => setCount(c => c + 1)}>
                Increment
            </button>
        </div>
    );
}
```

**Note:** Always use `clsx` for conditional classnames instead of string concatenation or template literals.

## Testing

Run tests:
```bash
bun test
```

Tests use Bun's built-in test framework:
```typescript
import { test, expect } from "bun:test";

test("example", () => {
    expect(1 + 1).toBe(2);
});
```

## Important Notes

1. **No external runtime dependencies** - Everything must be bundled
2. **Single entry point** - Each game has one default export
3. **Game name from directory** - Directory name becomes game name and URL path
4. **Hot reload** - Dev server rebuilds on each page reload
5. **Mobile support** - Use `?mobile=true` to enable Eruda debugger
6. **Production debugging** - Use `?production=true` to test production builds in dev

## Examples

Study existing games for patterns:
- **Simple**: `playground/` - Basic game loop example
- **Canvas**: `binario/` - Canvas-based puzzle game
- **Preact**: `ai-story/` - Complex app with components and state
- **WASM**: `life/` - C code compiled to WASM
- **Text-based**: `text-dungeon/` - Text adventure game

## Troubleshooting

### Build fails with "No entry point found"
- Ensure your game has `index.ts` or `index.tsx` with default export

### Assets not loading
- Check file extensions are supported
- Verify assets are in `src/games/<name>/assets/`

### WASM compilation fails
- Install clang and WASM toolchain
- Check C/C++ code compiles with `-Werror`

### TypeScript errors
- Run `bunx tsc --noEmit --skipLibCheck` to check types
- Use `@common/*` path alias for common imports
