# @playcademy/vite-plugin

**Vite plugin for Playcademy app development and deployment**

This plugin integrates Playcademy's development sandbox and build tools into your Vite workflow, automatically generating manifests, managing development environments, and creating deployment-ready archives.

## Overview

The Playcademy Vite plugin streamlines app development by providing:

- **Development Sandbox**: Automatically starts a local Playcademy API server during development.
- **Manifest Generation**: Creates required `playcademy.manifest.json` files for platform deployment
- **Build Optimization**: Configures Vite settings for optimal Playcademy platform compatibility
- **Deployment Packaging**: Optionally creates zip archives ready for platform upload

### Key Benefits

- **Zero-Config Development**: Works out of the box with sensible defaults
- **Hot Reload Integration**: Seamless development experience with Vite's hot module replacement
- **Platform Compatibility**: Ensures builds work correctly on the Playcademy platform
- **Type Safety**: Full TypeScript support with comprehensive type definitions
- **Flexible Configuration**: Extensive options for customizing both development and build processes

## Installation

Install the plugin in your Playcademy project:

```bash
# Using Bun (recommended)
bun add -D @playcademy/vite-plugin

# Using npm
npm install --save-dev @playcademy/vite-plugin

# Using yarn
yarn add --dev @playcademy/vite-plugin

# Using pnpm
pnpm add -D @playcademy/vite-plugin
```

## Quick Start

Add the plugin to your `vite.config.ts`:

```typescript
import { defineConfig } from 'vite'

import { playcademy } from '@playcademy/vite-plugin'

export default defineConfig({
    plugins: [
        playcademy(), // Uses all defaults
    ],
})
```

Start development:

```bash
bun dev
```

The plugin will:

- Start the sandbox server at `http://localhost:4321/api`
- Enable API integration for your app
- Provide hot reload for rapid development

## Configuration

### Basic Configuration

```typescript
import { playcademy } from '@playcademy/vite-plugin'

export default defineConfig({
    plugins: [
        playcademy({
            export: {
                autoZip: true, // Create deployment zip (enabled by default)
            },
            sandbox: {
                autoStart: true, // Start sandbox automatically
                verbose: false, // Enable debug logging
                logLevel: 'info', // Log level (debug, info, warn, error)
                seed: true, // Seed database with demo data
                recreateDb: false, // Recreate database on each start
                memoryOnly: false, // Use in-memory database
            },
        }),
    ],
})
```

### Disabling Auto-Zip

By default, the plugin creates a deployment archive. To disable:

```typescript
export default defineConfig({
    plugins: [
        playcademy({
            export: {
                autoZip: false, // Disable automatic zip creation
            },
        }),
    ],
})
```

### Custom Sandbox Configuration

```typescript
export default defineConfig({
    plugins: [
        playcademy({
            sandbox: {
                autoStart: false, // Disable auto-start
                url: 'http://localhost:8080', // Custom port
                verbose: true, // Enable verbose logging
                logLevel: 'debug', // Set log level (debug, info, warn, error)
            },
        }),
    ],
})
```

## Plugin Options

### Top-Level Options

| Option       | Type                         | Default      | Description                                  |
| ------------ | ---------------------------- | ------------ | -------------------------------------------- |
| `configPath` | `string`                     | `undefined`  | Path to playcademy.config.js (auto-detected) |
| `mode`       | `'platform' \| 'standalone'` | `'platform'` | Plugin operation mode                        |

**Mode Options:**

- `'platform'`: Full Playcademy experience with sandbox server, backend bundling, and shell wrapper (recommended)
- `'standalone'`: Backend bundling only, no platform features

### Export Options (`export`)

Configuration for build output:

| Option    | Type      | Default | Description                   |
| --------- | --------- | ------- | ----------------------------- |
| `autoZip` | `boolean` | `true`  | Create deployment zip archive |

### Sandbox Options (`sandbox`)

Configuration for the development sandbox server:

| Option         | Type                                     | Default                       | Description                             |
| -------------- | ---------------------------------------- | ----------------------------- | --------------------------------------- |
| `autoStart`    | `boolean`                                | `true`                        | Start sandbox during development        |
| `url`          | `string`                                 | `'http://localhost:4321/api'` | Sandbox server URL                      |
| `verbose`      | `boolean`                                | `false`                       | Enable verbose logging                  |
| `logLevel`     | `'debug' \| 'info' \| 'warn' \| 'error'` | `'info'`                      | Log level for sandbox server            |
| `recreateDb`   | `boolean`                                | `false`                       | Recreate database on each start         |
| `seed`         | `boolean`                                | `true`                        | Seed database with demo data            |
| `memoryOnly`   | `boolean`                                | `false`                       | Use in-memory database (non-persistent) |
| `databasePath` | `string`                                 | `undefined`                   | Custom path for database file           |

### Display Options (`display`)

Configuration for visual elements during development:

| Option      | Type      | Default | Description                             |
| ----------- | --------- | ------- | --------------------------------------- |
| `hideBadge` | `boolean` | `false` | Hide the Playcademy badge in the corner |

### TimeBack Options (`timeback`)

Configuration for TimeBack integration testing during local development. Set to `false` to explicitly disable TimeBack even if configured in playcademy.config.

| Option         | Type                                                                  | Default                 | Description                                       |
| -------------- | --------------------------------------------------------------------- | ----------------------- | ------------------------------------------------- |
| `id`           | `string`                                                              | auto-generated mock ID  | TimeBack student ID                               |
| `role`         | `'student' \| 'parent' \| 'teacher' \| 'administrator' \| 'guardian'` | `'student'`             | User role for testing different permission levels |
| `organization` | `'mock' \| object`                                                    | `'mock'`                | Organization (school/district) configuration      |
| `courses`      | `Record<string, 'mock' \| string \| null>`                            | all courses from config | Course enrollment overrides                       |

#### Organization Object Properties

| Property | Type                                                                         | Default                | Description            |
| -------- | ---------------------------------------------------------------------------- | ---------------------- | ---------------------- |
| `id`     | `string`                                                                     | `'PLAYCADEMY'`         | Organization sourcedId |
| `name`   | `string`                                                                     | `'Playcademy Studios'` | Organization name      |
| `type`   | `'school' \| 'district' \| 'department' \| 'local' \| 'state' \| 'national'` | `'department'`         | Organization type      |

#### TimeBack Configuration Example

```typescript
export default defineConfig({
    plugins: [
        playcademy({
            timeback: {
                // All courses from playcademy.config.js enrolled by default with mock IDs
                role: 'student', // Test as student (default)
            },
        }),
    ],
})

// Override specific courses
export default defineConfig({
    plugins: [
        playcademy({
            timeback: {
                courses: {
                    'FastMath:3': 'mock', // Mock enrollment for grade 3
                    'FastMath:4': null, // Exclude from enrollment (test partial)
                    'Science:5': 'real-course-id-123', // Real TimeBack course
                },
            },
        }),
    ],
})

// Full real TimeBack integration
export default defineConfig({
    plugins: [
        playcademy({
            timeback: {
                id: 'real-student-sourced-id',
                organization: {
                    id: 'real-org-id',
                    name: 'Springfield Elementary',
                    type: 'school',
                },
                courses: {
                    'FastMath:3': 'real-course-id-g3',
                    'FastMath:4': 'real-course-id-g4',
                },
            },
        }),
    ],
})
```

## CLI Hotkeys

During development, the plugin provides keyboard shortcuts in the terminal:

| Key | Description                                              |
| --- | -------------------------------------------------------- |
| `m` | Toggle between platform and standalone modes             |
| `d` | Recreate sandbox database (resets to fresh seeded state) |
| `p` | Cycle platform user role (player → developer → admin)    |
| `t` | Cycle TimeBack role (student → parent → teacher → admin) |

> **Note:** Some configuration changes require recreating the sandbox database to take effect. Press `d` after changing options like `timeback.id`, `timeback.organization`, or `timeback.courses` in your vite.config.ts.

## Build Output

### Development Mode

During `bun dev`, the plugin:

- Starts the sandbox server (if enabled)
- Provides API simulation
- Enables hot reload for your code
- Seamlessly wraps your app in the Playcademy environment

Console output:

```
VITE v6.3.5  ready in 500ms

➜  Local:   http://localhost:5173/
➜  Network: use --host to expose

PLAYCADEMY v1.2.3

➜  Project:  my-app
➜  Sandbox:  http://localhost:4321/api
```

**How it works**: When you visit `http://localhost:5173/` in your browser, you'll see your app wrapped in the Playcademy development shell (which mimics the production platform environment). Inside the iframe, your app is served at the root path `/`, so client-side routers (React Router, wouter, etc.) work naturally without any special configuration.

The plugin uses the `Sec-Fetch-Dest` header to intelligently detect whether a request is from the shell's iframe or top-level browser navigation, automatically serving the appropriate content.

**Client-side routing**: Both in development and production, your routers will see clean paths like `/` and `/game`. In production, the platform uses a runner that loads your app from the CDN while presenting clean routing paths. You don't need to configure anything - just write your routes normally:

```tsx
<Router>
    <Route path="/" component={Home} />
    <Route path="/game" component={Game} />
    <Route path="/settings" component={Settings} />
</Router>
```

**Runtime asset loading**: If your app loads assets dynamically at runtime (files that Vite can't analyze at build time), use the SDK's CDN helpers:

```typescript
import { PlaycademyClient } from '@playcademy/sdk'

const client = await PlaycademyClient.init()

// Load dynamic JSON data (e.g., level selected by user)
const levelData = await client.runtime.assets.json`levels/level-${levelId}.json`

// Load images dynamically using tagged template literals
img.src = client.runtime.assets.url`badges/${badgeType}.png`
audio.src = client.runtime.assets.url`sfx/${soundEffect}.wav`

// Or use regular function calls
const data = await client.runtime.assets.fetch('data/config.json')
const blob = await client.runtime.assets.blob('images/hero.png')
```

These helpers automatically resolve to the correct asset URLs in production and relative paths in local development.

### Production Build

During `bun run build`, the plugin:

- Generates `playcademy.manifest.json` in `dist/`
- Generates `.vite/manifest.json` for optimal asset loading
- Creates deployment zip (if `autoZip: true`)
- Optimizes build for platform deployment

Console output:

```
dist/index.html                           2.45 kB │ gzip:  1.12 kB
dist/assets/index-Bj8fxu6c.js           135.24 kB │ gzip: 43.82 kB

[Playcademy]
playcademy.manifest.json                   0.25 kB
.playcademy/my-game.zip                1,234.56 kB
```

## Generated Files

### Manifest File

The plugin generates `dist/playcademy.manifest.json`:

```json
{
    "version": "1",
    "platform": "web",
    "createdAt": "2024-01-01T12:00:00.000Z"
}
```

### Deployment Archive

By default, the plugin creates `.playcademy/{project-name}.zip` containing all build files ready for platform upload. This can be disabled by setting `autoZip: false`.

## Development

### Development Workflow

```bash
# Start the development environment from monorepo root
bun dev

# This starts all applications with proper port allocation:
# - Landing: http://localhost:5173
# - Hub: http://localhost:5174
# - Docs: http://localhost:5175
# - Blog: http://localhost:5176
# - Sandbox: http://localhost:4321
```

For package-specific development:

```bash
# Change to package directory
cd packages/vite-plugin

# Build the plugin
bun run build
```

Package releases are handled by the monorepo Changesets and CI release workflows rather than from this package directory.

## Dependencies

### Runtime Dependencies

- **archiver**: Zip file creation for deployment packages
- **picocolors**: Terminal color output for logging

### Development Dependencies

- **@playcademy/sandbox**: Development sandbox server
- **@types/archiver**: TypeScript definitions for archiver
- **yocto-spinner**: Progress indicators for build operations

### Peer Dependencies

- **typescript**: TypeScript compiler (v5+)

## Common Use Cases

### Basic Web App

```typescript
// Minimal configuration for most web games
export default defineConfig({
    plugins: [playcademy()],
})
```

### Testing with Clean Database

```typescript
// Start with a fresh database on each dev server restart
export default defineConfig({
    plugins: [
        playcademy({
            sandbox: {
                recreateDb: true, // Recreate database on each start
            },
        }),
    ],
})
```

### In-Memory Database for CI

```typescript
// Use in-memory database for fast, ephemeral testing
export default defineConfig({
    plugins: [
        playcademy({
            sandbox: {
                memoryOnly: true, // Database in RAM only
            },
        }),
    ],
})
```

### Godot Export

```typescript
// Configuration for Godot HTML5 exports
export default defineConfig({
    plugins: [
        playcademy({
            export: {
                platform: 'godot',
                entryPoint: 'game.html',
            },
        }),
    ],
})
```

### Mode-Based Configuration

```typescript
// Different settings for development vs production
export default defineConfig(({ mode }) => ({
    plugins: [
        playcademy({
            sandbox: {
                verbose: mode === 'development',
            },
        }),
    ],
}))
```

### TimeBack Integration

```typescript
// Test TimeBack enrollments and role-based features
export default defineConfig({
    plugins: [
        playcademy({
            timeback: {
                // id defaults to auto-generated mock ID
                courses: {
                    'FastMath:3': 'mock',
                    'FastMath:4': 'mock',
                },
                role: 'student',
            },
        }),
    ],
})
```

During development, press `t` in the terminal to cycle through roles (student → parent → teacher → administrator → guardian) and test different permission levels. The browser reloads automatically.

## Troubleshooting

### Common Issues

**Manifest not generated**

- Ensure plugin is properly configured in `vite.config.ts`
- Check for build errors in console output
- Verify the build completes successfully

**Zip file not created**

- Auto-zip is enabled by default - check that build completed without errors
- Look for zip in `.playcademy/` directory
- If you previously disabled it, remove `autoZip: false` from export options

### Debug Mode

Enable verbose logging for troubleshooting:

```typescript
playcademy({
    sandbox: {
        verbose: true,
    },
})
```
