@playcademy/sandbox
API reference for the Playcademy Sandbox
@playcademy/sandbox
Local development server for isolated Playcademy game development.
The Playcademy sandbox provides a complete local simulation of the Playcademy platform API for development and testing.
What is the Sandbox?
The sandbox is a local development server that lets you:
- Develop games locally with full platform integration.
- Test SDK functionality without needing the live platform.
- Simulate user accounts and game data in a controlled environment.
- Work offline without an internet connection.
It's a "mock Playcademy platform" running on your machine that behaves just like the real thing.
Key Benefits
- Isolated Environment: Completely local execution with no external dependencies.
- Zero Configuration: Automatic database setup and seeding.
- Full API Compatibility: All Playcademy APIs available locally.
- Fast Development Cycle: Quick startup with persistent local database.
How It Works
The sandbox runs a local API server to provide a complete development environment. When using our Vite templates, this is handled automatically.
graph TD
subgraph "Your Machine"
A["Your Game (in browser)"] --> B["@playcademy/sdk"];
B --> C["API Server (localhost:4321)"];
C --> D["Local PGlite Database"];
endUsage
The easiest way to use the sandbox is with our official Vite templates, which handle everything automatically via the @playcademy/vite-plugin. You can also run it manually as a standalone CLI for advanced use cases.
Automatic Setup (Recommended)
When you start your development server with bun dev, the Vite plugin will launch the sandbox in the background.
::: code-group
bun devpnpm devyarn devnpm run dev:::
You'll see output confirming that the sandbox is running:
VITE v6.3.5
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
PLAYCADEMY v0.1.0
➜ Game: playground
➜ Sandbox: http://localhost:4321/api// vite.config.ts
import { defineConfig } from 'vite'
import { playcademy } from '@playcademy/vite-plugin'
export default defineConfig({
plugins: [
playcademy({
sandbox: {
autoStart: true,
},
}),
],
})Manual Setup
You can run the sandbox as a standalone process from the command line.
::: code-group
# Run with defaults
bunx @playcademy/sandbox
# Run with custom port and verbose logging
bunx @playcademy/sandbox --port 8080 --verbosepnpm dlx @playcademy/sandbox --port 8080 --verboseyarn dlx @playcademy/sandbox --port 8080 --verbosenpx @playcademy/sandbox --port 8080 --verbose:::
Command-Line Options
| Option | Alias | Description | Default |
|---|---|---|---|
--port <number> | -p | Port for the API server. | 4321 |
--verbose | -v | Enables verbose logging for debugging. | false |
--quiet | -q | Quiet mode (suppress interactive output) | false |
--no-seed | Disables seeding of demo data. | seeds | |
--recreate-db | Recreate the on-disk database on start. | false | |
--memory | Use in-memory database (no persistence). | false | |
--db-path <path> | Custom path for the database file. | undefined | |
--config-path <path> | Path to playcademy.config.json. | cwd | |
--project-name <name> | Sets the project name for game seeding. | undefined | |
--project-slug <slug> | Sets the project slug for game seeding. | undefined |
Manual SDK Configuration
If you run the sandbox manually, you'll need to configure the SDK client to point to it.
import { PlaycademyClient } from '@playcademy/sdk'
const client = await PlaycademyClient.init({
baseUrl: 'http://localhost:4321/api',
// In manual mode, you must provide a mock token
token: 'mock-dev-token',
})Sandbox Features
| Feature | Description |
|---|---|
| API Simulation | Emulates the entire Playcademy backend API for users, games, inventory, etc. |
| Data Persistence | Persists data to disk by default (survives restarts). Use --recreate-db to reset, --memory for in-memory only, or --db-path for custom location. |
| Mock Data | Automatically seeds with demo users and data on first run or when database is empty. |
| Game Context | When run via the Vite plugin, it automatically registers your current project as a mock game. |
Server Endpoints
Once running, the sandbox provides several key endpoints:
- Health Check:
GET /health - API Base URL:
/api
All production Playcademy APIs are available under the /api prefix, including /users, /games, /inventory, and more.
TimeBack Integration Testing
The sandbox supports TimeBack integration testing in three modes: mock (offline), local (Docker), and remote (real TimeBack API).
TimeBack Modes
| Mode | Description |
|---|---|
| Mock | No external dependencies, works offline. Uses generated mock data. |
| Local | Connect to a local TimeBack instance (Docker). |
| Remote | Real course IDs + API credentials. Tests against actual TimeBack API. |
| Disabled | No TimeBack config. TimeBack routes return errors. |
CLI Options
When running the sandbox standalone, configure TimeBack via CLI flags:
# Local TimeBack (Docker)
bunx @playcademy/sandbox \
--timeback-local \
--timeback-oneroster-url http://localhost:8080/ims/oneroster \
--timeback-caliper-url http://localhost:8080/caliper \
--timeback-student-id your-student-id
# Remote TimeBack (requires env vars for credentials)
bunx @playcademy/sandbox \
--timeback-student-id your-student-sourcedId| Option | Description |
|---|---|
--timeback-local | Enable local TimeBack mode (Docker) |
--timeback-oneroster-url <url> | OneRoster API URL |
--timeback-caliper-url <url> | Caliper API URL |
--timeback-course-id <id> | Course ID for enrollments |
--timeback-student-id <id> | Student ID to link to demo user |
--timeback-role <role> | User role (student, parent, teacher, administrator) |
--timeback-org-id <id> | Organization ID |
--timeback-org-name <name> | Organization display name |
--timeback-org-type <type> | Organization type (school, district, department, etc.) |
Environment Variables
For remote TimeBack (or as alternative to CLI flags):
# TimeBack API credentials (required for remote mode)
TIMEBACK_ONEROSTER_API_URL=https://api.timeback.org/ims/oneroster
TIMEBACK_API_CLIENT_ID=your-client-id
TIMEBACK_API_CLIENT_SECRET=your-client-secret
TIMEBACK_API_AUTH_URL=https://auth.timeback.org
# Link sandbox demo user to a real TimeBack student
SANDBOX_TIMEBACK_STUDENT_ID=your-student-sourcedId
SANDBOX_TIMEBACK_COURSE_ID=your-course-idWith Vite Plugin
When using @playcademy/vite-plugin, TimeBack enrollments and roles can be configured directly in vite.config.ts for a streamlined experience. See the Vite plugin documentation for details.
The Vite plugin also provides a t hotkey to cycle through TimeBack roles during development.
Runtime Testing
Once configured, your game can use the SDK to submit activities:
await client.timeback.endActivity({
correctQuestions: 8,
totalQuestions: 10,
})Note on CLI Commands:
The sandbox provides TimeBack management endpoints, but CLI commands (playcademy timeback setup, verify) require Better Auth authentication and won't work against the sandbox. These commands should be run against the platform.
Available TimeBack Endpoints
The sandbox provides these TimeBack endpoints (matching production platform):
Management:
GET /api/timeback/integrations/:gameId- Get integration detailsPOST /api/timeback/setup- Create TimeBack integrationDELETE /api/timeback/integrations/:gameId- Delete integrationGET /api/timeback/verify/:gameId- Verify OneRoster resourcesGET /api/timeback/config/:gameId- Get TimeBack configuration
Runtime:
POST /api/timeback/end-activity- Submit activity results
XP Queries:
GET /api/timeback/xp/today- Get today's XPPUT /api/timeback/xp/today- Update today's XPGET /api/timeback/xp/total- Get total XPGET /api/timeback/xp/history- Get XP history
These use the same api-core handlers as the production platform, ensuring consistency.
When properly configured, your game can call client.timeback.endActivity() during local development and see real events appear in your TimeBack dashboard.
Debugging
Health Check
You can verify the sandbox API server is running by sending a request to its /health endpoint.
curl -sSL http://localhost:4321/health | jqThis should return a JSON object with the status:
{
"status": "ok",
"timestamp": "2023-10-27T00:00:00.000Z"
}Common Issues
| Issue | Solution |
|---|---|
| Sandbox doesn't start | When using Vite, check that autoStart: true in vite.config.ts and @playcademy/vite-plugin is installed. Check terminal for errors. |
| API calls return HTML | This indicates the API server isn't running or is on a different port. Check your sandbox url configuration. |
| Port conflicts | The sandbox uses port 4321 by default. If another process is using this port, stop it or use --port to specify a different port. |
| Data persists unexpectedly | By default, the sandbox persists data to disk. Use --recreate-db to reset the database, or --memory for session-only data that doesn't persist. |
Production vs. Sandbox
The SDK is designed to work seamlessly in both environments. PlaycademyClient.init() automatically detects whether it's running in a production environment or against a local sandbox.
| Feature | Sandbox | Production |
|---|---|---|
| Data | Mock, temporary | Real user data |
| Authentication | Mock tokens | Secure authentication |
| Persistence | Local disk (default) or session-only (--memory) | Permanent cloud database |
Contributing
The sandbox is a crucial development tool for the Playcademy ecosystem. For contribution guidelines, see the monorepo CONTRIBUTING.md.
Variables
version
const version: string = packageJson.version;Defined in: index.ts:25
Functions
startServer()
function startServer(
port,
project?,
options?): Promise<{
gameId: undefined | string;
main: ServerType;
reset: () => Promise<void>;
setRole: (role) => void;
stop: () => Promise<void>;
timebackMode: null | "local" | "remote" | "mock";
}>;Defined in: index.ts:35
Start the sandbox server
Parameters
port
number
Port to listen on
project?
ProjectInfo
Optional project information for seeding
options?
Omit<ServerOptions, "port" | "project"> = {}
Server configuration options
Returns
Promise<{
gameId: undefined | string;
main: ServerType;
reset: () => Promise<void>;
setRole: (role) => void;
stop: () => Promise<void>;
timebackMode: null | "local" | "remote" | "mock";
}>
Server instance with stop method
