Skip to main content

Overview

The ChatGPTSimulator component provides a local development environment that replicates the MCP App runtime used by hosts like ChatGPT. It renders your resources inside iframes, matching the production hosting behavior.

Import

import 'sunpeak/style.css'; // Required to style the simulator.
import { ChatGPTSimulator } from 'sunpeak';

Basic Usage

For projects using the sunpeak framework, simulations are auto-discovered. Just run:
sunpeak dev
For custom setups, you can manually configure the simulator:
import { ChatGPTSimulator } from 'sunpeak/chatgpt';
import { resource } from './resources/example/example-resource';
import exampleSimulation from './resources/example/example-show-simulation.json';

// Combine simulation with resource
const simulations = [{
  ...exampleSimulation,
  resource,
  resourceUrl: 'http://localhost:3000/resources/example',
}];

<ChatGPTSimulator
  simulations={simulations}
  appName="My App"
  appIcon="🌄"
/>

Props

simulations
Record<string, Simulation>
Object mapping simulation names to their definitions. See Simulation API Reference for details.
appName
string
default:"Sunpeak App"
Name of the app displayed in the simulator UI.
appIcon
string
Optional icon (emoji) displayed in the simulator UI.
children
React.ReactNode
Optional children to render when no simulations are selected.

URL Parameters

The ChatGPT Simulator supports URL parameters for configuring the initial state. This is especially useful for automated testing and sharing specific configurations.

Supported Parameters

ParameterTypeDefaultDescription
simulationstringFirst simulationSimulation name to load
theme'light' | 'dark''dark'Color theme
displayMode'inline' | 'pip' | 'fullscreen''inline'App display mode
localestring'en-US'Locale for i18n
maxHeightnumber600Max height in PiP mode
deviceType'mobile' | 'tablet' | 'desktop' | 'unknown''desktop'Device type
hover'true' | 'false''true'Hover capability
touch'true' | 'false''false'Touch capability
safeAreaTopnumber0Top safe area inset
safeAreaBottomnumber0Bottom safe area inset
safeAreaLeftnumber0Left safe area inset
safeAreaRightnumber0Right safe area inset
viewMode'modal' | 'default'-View mode

Example URLs

# Load albums simulation in light mode
http://localhost:3000/?simulation=albums-show&theme=light

# Fullscreen dark mode
http://localhost:3000/?simulation=review-diff&theme=dark&displayMode=fullscreen

# Mobile simulation with touch
http://localhost:3000/?simulation=map-show&deviceType=mobile&touch=true&hover=false

createSimulatorUrl

For type-safe URL generation in tests, use the createSimulatorUrl utility from sunpeak/chatgpt:

Import

import { createSimulatorUrl } from 'sunpeak/chatgpt';

Usage

// Basic usage
createSimulatorUrl({ simulation: 'albums-show', theme: 'light' })
// Returns: '/?simulation=albums-show&theme=light'

// With display mode
createSimulatorUrl({
  simulation: 'review-diff',
  theme: 'dark',
  displayMode: 'fullscreen',
})
// Returns: '/?simulation=review-diff&theme=dark&displayMode=fullscreen'

// With device simulation
createSimulatorUrl({
  simulation: 'map-show',
  deviceType: 'mobile',
  touch: true,
  hover: false,
})
// Returns: '/?simulation=map-show&deviceType=mobile&touch=true&hover=false'

// With safe area insets (for notch simulation)
createSimulatorUrl({
  simulation: 'carousel-show',
  safeAreaTop: 44,
  safeAreaBottom: 34,
})
// Returns: '/?simulation=carousel-show&safeAreaTop=44&safeAreaBottom=34'

SimulatorUrlParams Interface

interface SimulatorUrlParams {
  simulation?: string;
  theme?: 'light' | 'dark';
  displayMode?: 'inline' | 'pip' | 'fullscreen';
  locale?: string;
  maxHeight?: number;
  deviceType?: 'mobile' | 'tablet' | 'desktop' | 'unknown';
  hover?: boolean;
  touch?: boolean;
  safeAreaTop?: number;
  safeAreaBottom?: number;
  safeAreaLeft?: number;
  safeAreaRight?: number;
  viewMode?: 'modal' | 'default';
}

E2E Testing Example

import { test, expect } from '@playwright/test';
import { createSimulatorUrl } from 'sunpeak/chatgpt';

test.describe('Albums Resource', () => {
  test('should render in light mode', async ({ page }) => {
    await page.goto(createSimulatorUrl({
      simulation: 'albums-show',
      theme: 'light',
    }));

    const albumCard = page.locator('button:has-text("Summer Slice")');
    await expect(albumCard).toBeVisible();
  });

  test('should render in fullscreen dark mode', async ({ page }) => {
    await page.goto(createSimulatorUrl({
      simulation: 'albums-show',
      theme: 'dark',
      displayMode: 'fullscreen',
    }));

    // Verify fullscreen behavior
    const expandButton = page.locator('button[aria-label="Enter fullscreen"]');
    await expect(expandButton).not.toBeVisible();
  });
});
The simulator sidebar provides interactive controls for:
  • Simulation: Select which simulation to display
  • Simulation Width: Toggle between mobile (375px, 425px), tablet (768px), and full width (1024px)
  • Theme: Toggle between light and dark themes
  • Display Mode: Switch between inline, PiP, and fullscreen modes
  • Locale: Set the locale string
  • Max Height: Configure PiP mode height
  • Device Type: Configure device type and capabilities (hover, touch)
  • Safe Area Insets: Configure safe area insets for notch simulation
  • View Mode: Toggle between default and modal views
  • JSON Editors: Edit tool input, output, metadata, and host context directly