Skip to content

Tutorial 2: Interactive Balloon Clicker Game ​

Build an interactive demo showcasing component-to-component communication with three separate components.

What You'll Build ​

An interactive demo board with three communicating components:

  1. clicker-button - Button that emits click events
  2. balloon-viewer - Balloon that grows when it receives click events and pops at max size
  3. score-display - Counter that increments on each click

Difficulty: Intermediate Time: 45 minutes Prerequisites: Quick Start Tutorial

Preview ​

The demo creates a horizontal layout: Button β†’ Balloon β†’ Score

When you click the button:

  • The balloon grows larger (up to 10 clicks)
  • The score increments
  • When balloon reaches max size, it pops and resets

Learning Goals

  • Component-to-component communication via events
  • Event system (postMessage API)
  • Props configuration for components
  • Horizontal layout design on a board
  • Building reusable components that work together

Try It Live ​

The fastest way to try this demo:

bash
./scripts/demo/create-balloon-game-demo.sh

This creates a demo board with all three components already configured and positioned.

Architecture Overview ​

This tutorial demonstrates 3 independent components working together:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Clicker Button  β”‚      β”‚ Balloon Viewer  β”‚      β”‚ Score Display   β”‚
β”‚                 β”‚      β”‚                 β”‚      β”‚                 β”‚
β”‚  [Click Me!]    │─────▢│    ☁️ Balloon   β”‚      β”‚   Score: 0      β”‚
β”‚                 β”‚      β”‚   (grows)       β”‚      β”‚                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                        β”‚                        β”‚
         β”‚                        β”‚                        β”‚
         β–Ό                        β–Ό                        β–Ό
    emits:                   listens:                 listens:
  action:click             action:click             action:click
                           emits:
                         action:pop

Components Breakdown ​

1. Clicker Button (clicker-button@1.0.0) ​

Purpose: Clickable button that emits events when clicked.

Props:

  • buttonText (string, optional): Button label text
  • maxClicks (number, default: 10): Maximum number of clicks before auto-reset

Events Emitted:

  • action:click - Fired on each button click with { clickCount: number }

Dimensions: 200px Γ— 360px

Example manifest.json:

json
{
  "name": "clicker-button",
  "version": "1.0.0",
  "description": "Clickable button that emits action events",
  "entry": "index.html",
  "component": {
    "width": 200,
    "height": 360,
    "resizable": false,
    "schema": {
      "type": "object",
      "properties": {
        "buttonText": {
          "type": "string",
          "default": "",
          "description": "Button label text"
        },
        "maxClicks": {
          "type": "number",
          "default": 10,
          "description": "Max clicks before reset"
        }
      }
    }
  }
}

2. Balloon Viewer (balloon-viewer@1.0.0) ​

Purpose: Displays a balloon that grows when receiving click events, pops at max size.

Props:

  • balloonColor (string, default: "#f56565"): Balloon color (hex)
  • maxSize (number, default: 10): Maximum size before pop

Events Listened:

  • action:click - Grows balloon on each event

Events Emitted:

  • action:pop - Fired when balloon reaches maxSize and pops

Dimensions: 280px Γ— 360px

Example manifest.json:

json
{
  "name": "balloon-viewer",
  "version": "1.0.0",
  "description": "Balloon that grows on click events and pops",
  "entry": "index.html",
  "component": {
    "width": 280,
    "height": 360,
    "resizable": false,
    "schema": {
      "type": "object",
      "properties": {
        "balloonColor": {
          "type": "string",
          "default": "#f56565",
          "description": "Balloon color (hex)"
        },
        "maxSize": {
          "type": "number",
          "default": 10,
          "description": "Max size before pop"
        }
      }
    }
  }
}

3. Score Display (score-display@1.0.0) ​

Purpose: Displays click counter that increments on each click event.

Props:

  • label (string, optional): Label text above score

Events Listened:

  • action:click - Increments counter

Dimensions: 180px Γ— 360px

Example manifest.json:

json
{
  "name": "score-display",
  "version": "1.0.0",
  "description": "Score counter display",
  "entry": "index.html",
  "component": {
    "width": 180,
    "height": 360,
    "resizable": false,
    "schema": {
      "type": "object",
      "properties": {
        "label": {
          "type": "string",
          "default": "",
          "description": "Label text"
        }
      }
    }
  }
}

How Communication Works ​

Event Flow ​

When a user clicks the button:

  1. clicker-button emits action:click event via postMessage
  2. BoardAPI broadcasts the event to all components on the board
  3. balloon-viewer receives event β†’ grows balloon size
  4. score-display receives event β†’ increments counter
  5. When balloon reaches maxSize, balloon-viewer emits action:pop

postMessage API ​

All components communicate using window.parent.postMessage:

javascript
// Emit event (from clicker-button)
window.parent.postMessage({
  type: 'component-event',
  event: 'action:click',
  data: { clickCount: 5 }
}, '*');

// Listen for events (in balloon-viewer)
window.addEventListener('message', (event) => {
  if (event.data.type === 'board-event' &&
      event.data.event === 'action:click') {
    // Grow balloon
    growBalloon();
  }
});

See: Event System API for full reference.

Creating the Demo Board ​

bash
./scripts/demo/create-balloon-game-demo.sh

What this does:

  • Creates a new board with is_demo: true and is_sandbox: true
  • Positions 3 components in horizontal layout
  • Configures props for each component
  • Adds tutorial prompts and docs links
  • Returns board UUID and host link

Option 2: Manual API Call ​

bash
curl -X POST http://localhost:4000/api/v1/boards \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d @scripts/demo/configs/balloon-game.json

The config file contains:

  • Board metadata (is_demo, is_sandbox)
  • Tutorial steps configuration
  • Documentation links
  • Initial state with 3 components positioned

Option 3: Step-by-Step Manual Creation ​

Step 1: Create empty board

bash
curl -X POST http://localhost:4000/api/v1/boards \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Balloon Game Demo",
    "is_public": true,
    "is_sandbox": true
  }'

Step 2: Add clicker-button (position x:70, y:100)

Via WebSocket or direct API call with:

json
{
  "objectId": "clicker-btn-1",
  "type": "external-component",
  "position": { "x": 70, "y": 100 },
  "width": 200,
  "height": 360,
  "data": {
    "componentUrl": "http://localhost:4000/components/clicker-button@1.0.0/index.html",
    "props": {
      "buttonText": "",
      "maxClicks": 10
    }
  }
}

Step 3: Add balloon-viewer (position x:290, y:100)

json
{
  "objectId": "balloon-1",
  "type": "external-component",
  "position": { "x": 290, "y": 100 },
  "width": 280,
  "height": 360,
  "data": {
    "componentUrl": "http://localhost:4000/components/balloon-viewer@1.0.0/index.html",
    "props": {
      "balloonColor": "#f56565",
      "maxSize": 10
    }
  }
}

Step 4: Add score-display (position x:590, y:100)

json
{
  "objectId": "score-1",
  "type": "external-component",
  "position": { "x": 590, "y": 100 },
  "width": 180,
  "height": 360,
  "data": {
    "componentUrl": "http://localhost:4000/components/score-display@1.0.0/index.html",
    "props": {
      "label": ""
    }
  }
}

Testing the Demo ​

  1. Open the board host link in browser
  2. Click the "Click Me!" button
  3. Watch the balloon grow
  4. See the score increment
  5. After 10 clicks, balloon pops and resets

Expected behavior:

  • Each click triggers both balloon growth AND score increment
  • Balloon visual size increases proportionally (1/10, 2/10, ... 10/10)
  • At click 10, balloon pops with animation
  • Score continues counting even after balloon pops

Component Examples ​

For detailed implementation of each component, see:

Key Takeaways ​

Benefits of Multi-Component Architecture ​

  1. Reusability: Each component can be used independently
  2. Modularity: Easy to add/remove components without breaking others
  3. Testing: Test each component in isolation
  4. Maintainability: Update one component without touching others

Event-Driven Design ​

  • Components are loosely coupled via events
  • No direct component-to-component references
  • BoardAPI acts as event bus
  • Easy to add new components that respond to same events

Layout Flexibility ​

  • Components positioned absolutely on canvas
  • Easy to rearrange via drag-and-drop
  • Responsive to board zoom/pan

Next Steps ​

Ready for more complex integrations?

Troubleshooting ​

Events not firing:

  • Check browser console for postMessage errors
  • Verify component URLs are correct and accessible
  • Ensure components are loaded (check iframe status)

Balloon not growing:

  • Check balloon-viewer is listening to action:click events
  • Verify event data structure matches expected format
  • Check props: maxSize should be > 0

Score not incrementing:

  • Verify score-display component received event
  • Check browser console for JavaScript errors
  • Ensure component initialized properly

Components not communicating:

  • All components must be on same board
  • Check postMessage origin (should be '*' or specific origin)
  • Verify BoardAPI is broadcasting events correctly

Next: Restaurant Menu Tutorial - Learn to integrate external data sources