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:
- clicker-button - Button that emits click events
- balloon-viewer - Balloon that grows when it receives click events and pops at max size
- 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 (
postMessageAPI) - 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:
./scripts/demo/create-balloon-game-demo.shThis 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:popComponents Breakdown β
1. Clicker Button (clicker-button@1.0.0) β
Purpose: Clickable button that emits events when clicked.
Props:
buttonText(string, optional): Button label textmaxClicks(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:
{
"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:
{
"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:
{
"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:
- clicker-button emits
action:clickevent viapostMessage - BoardAPI broadcasts the event to all components on the board
- balloon-viewer receives event β grows balloon size
- score-display receives event β increments counter
- When balloon reaches
maxSize, balloon-viewer emitsaction:pop
postMessage API β
All components communicate using window.parent.postMessage:
// 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 β
Option 1: Automated Script (Recommended) β
./scripts/demo/create-balloon-game-demo.shWhat this does:
- Creates a new board with
is_demo: trueandis_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 β
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.jsonThe 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
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:
{
"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)
{
"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)
{
"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 β
- Open the board host link in browser
- Click the "Click Me!" button
- Watch the balloon grow
- See the score increment
- 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 β
- Reusability: Each component can be used independently
- Modularity: Easy to add/remove components without breaking others
- Testing: Test each component in isolation
- 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?
- Tutorial 3: Restaurant Menu - Learn external data integration
- Tutorial 4: Production Integration - Deploy with webhooks
- Component Communication Guide - Deep dive into event system
Related Documentation β
- Component Structure - File organization and manifest reference
- Publishing Components - How to upload your components
- Event System API - Complete event system reference
- Demo & Sandbox Mode - Learn about demo boards
Troubleshooting β
Events not firing:
- Check browser console for
postMessageerrors - Verify component URLs are correct and accessible
- Ensure components are loaded (check iframe status)
Balloon not growing:
- Check balloon-viewer is listening to
action:clickevents - Verify event data structure matches expected format
- Check props:
maxSizeshould 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
postMessageorigin (should be '*' or specific origin) - Verify BoardAPI is broadcasting events correctly
Next: Restaurant Menu Tutorial - Learn to integrate external data sources