This chapter covers interactive controls that allow users to manipulate MicroSim parameters. You will learn to create sliders and buttons using createSlider() and createButton(), implement start/stop/pause/reset functionality, and handle mouse and keyboard events. The chapter explores event handlers, the isRunning state pattern for animation control, and techniques for speed control and parameter adjustment. These skills enable you to create truly interactive educational simulations.
Concepts Covered
This chapter covers the following 20 concepts from the learning graph:
Welcome to the chapter where you finally take control—literally! A MicroSim without user controls is like a car without a steering wheel: it might go somewhere, but you have no say in where. By the end of this chapter, you'll have complete control over how users control the controls in your simulations.
Every educational MicroSim needs user interaction. Students learn best when they can experiment, adjust parameters, and see immediate results. The controls you add transform passive viewers into active explorers.
The Control Principle
The best controls are ones users don't have to think about. When controls are intuitive and consistent, students focus on the concept—not the interface. Keep your controls under control!
The Two Essential Controls: Sliders and Buttons
In the world of MicroSims, two controls rule supreme:
Control Type
Best For
User Action
Sliders
Continuous values (speed, size, angle)
Drag to adjust
Buttons
Discrete actions (start, stop, reset)
Click to trigger
Together, sliders and buttons give users complete control over any simulation. Let's master each one.
Slider Control: The Continuous Commander
A slider control lets users select a value from a continuous range by dragging a handle. Sliders are perfect for parameters that vary smoothly—like speed, gravity, temperature, or any numeric value.
Why Sliders Work
Sliders provide:
Visual feedback: The handle position shows the current value
Intuitive interaction: Drag right for more, left for less
Bounded input: Users can't enter invalid values
Immediate response: Changes apply as you drag
The createSlider() Function
The createSlider() function creates a slider control:
letspeedSlider;letdrawHeight=350;letcontrolHeight=50;functionsetup(){createCanvas(400,drawHeight+controlHeight);// Create slider: range 1-10, default 5, step 0.5speedSlider=createSlider(1,10,5,0.5);speedSlider.position(100,drawHeight+15);speedSlider.size(200);// Width in pixels}functiondraw(){background(240,248,255);// Control regionfill(255);noStroke();rect(0,drawHeight,width,controlHeight);// Get current valueletspeed=speedSlider.value();// Display label and valuefill(0);textSize(14);textAlign(LEFT,CENTER);text("Speed:",20,drawHeight+25);textAlign(RIGHT,CENTER);text(speed.toFixed(1),width-20,drawHeight+25);// Use the value in your simulation// ...}
Slider Styling and Positioning
Sliders need careful positioning in the control region:
1234567
// Standard slider positioning patternletsliderLeftMargin=100;// Space for labelfunctionrepositionSlider(){speedSlider.position(sliderLeftMargin,drawHeight+15);speedSlider.size(canvasWidth-sliderLeftMargin-60);// Leave room for value}
<summary>Interactive Slider Playground</summary>
Type: microsim
Learning objective: Allow students to experiment with slider parameters (min, max, default, step) and see immediate effects (Bloom: Apply)
Canvas layout:
- Drawing area: 400x300 pixels
- Control area: 100 pixels (multiple control rows)
Visual elements:
- Main display: A circle whose size is controlled by a slider
- Current value displayed prominently
- Min/max markers on slider track
- Step indicators (tick marks when step > 1)
Meta-controls (controls that control the slider!):
- Input field: "Min value" (changes slider minimum)
- Input field: "Max value" (changes slider maximum)
- Input field: "Step size" (changes increment)
- The main slider updates when meta-controls change
Behavior:
- Changing min/max rebuilds the slider
- Step size shows as tick marks
- Circle size responds to slider value
- Shows how slider parameters affect behavior
Educational annotations:
- "Smaller step = finer control" when step < 1
- "Larger range = coarser control" when range > 100
- Live code display showing current createSlider() call
Color scheme:
- Circle: blue with white stroke
- Slider track: gray
- Value display: black
Implementation: p5.js with createSlider() and input fields
Button Control: The Discrete Decision Maker
A button control triggers a specific action when clicked. Unlike sliders that adjust values continuously, buttons execute commands: start, stop, reset, change mode.
Why Buttons Work
Buttons provide:
Clear action: One click, one result
Visible state: Labels tell users what will happen
Feedback: Visual response confirms the click
Simplicity: No ambiguity about what happens
The createButton() Function
The createButton() function creates a clickable button:
letstartButton;letcounter=0;functionsetup(){createCanvas(400,400);startButton=createButton('Click Me!');startButton.position(150,360);startButton.mousePressed(handleClick);}functionhandleClick(){counter++;// Increment on each click}functiondraw(){background(240,248,255);// Display click counttextSize(32);textAlign(CENTER,CENTER);fill(0);text("Clicks: "+counter,width/2,height/2);}
The stop button halts the animation completely (often resetting to initial state):
1 2 3 4 5 6 7 8 91011
letstopButton;functionsetup(){stopButton=createButton('Stop');stopButton.mousePressed(stopAnimation);}functionstopAnimation(){isRunning=false;resetToInitialState();// Also reset}
Pause Button
The pause button freezes the animation without resetting—so users can resume later:
The reset button returns all parameters to their default values:
1 2 3 4 5 6 7 8 9101112131415161718192021
letresetButton;functionsetup(){resetButton=createButton('Reset');resetButton.mousePressed(resetSimulation);}functionresetSimulation(){// Reset all variables to initial valuesball.x=initialX;ball.y=initialY;ball.vx=0;ball.vy=0;// Reset sliders to defaultsspeedSlider.value(5);gravitySlider.value(0.5);// Stop animationisRunning=false;}
The Complete Button Family
Button
Action
State Change
Label Change
Start
Begin animation
isRunning → true
"Start" → "Running"
Stop
Halt and reset
isRunning → false
Optional
Pause
Freeze in place
isPaused toggle
"Pause" ↔ "Resume"
Reset
Restore defaults
All values reset
Usually static
Input Handling: The Big Picture
Input handling is the overall process of detecting and responding to user actions. In p5.js, input comes from three main sources:
DOM Controls: Sliders, buttons, text inputs
Mouse Events: Clicks, drags, movement
Keyboard Events: Key presses and releases
Each input type uses a different handling pattern:
Mouse events let users interact directly with the canvas—clicking on objects, dragging elements, and responding to cursor position.
The mousePressed() Function
The mousePressed() function runs once when the user clicks:
1 2 3 4 5 6 7 8 91011
functionmousePressed(){// Check if click is in drawing areaif(mouseY<drawHeight){// Create new object at click positionobjects.push({x:mouseX,y:mouseY,size:20});}}
Using mouseX and mouseY
p5.js provides real-time cursor position:
Variable
Description
mouseX
Current horizontal position
mouseY
Current vertical position
pmouseX
Previous frame's X position
pmouseY
Previous frame's Y position
mouseIsPressed
Boolean: is button held down?
The mouseDragged() Function
The mouseDragged() function runs continuously while dragging:
1 2 3 4 5 6 7 8 910111213141516171819202122232425
letdragging=false;letdragObject=null;functionmousePressed(){// Check if we clicked on an objectfor(letobjofobjects){if(dist(mouseX,mouseY,obj.x,obj.y)<obj.size/2){dragging=true;dragObject=obj;break;}}}functionmouseDragged(){if(dragging&&dragObject){dragObject.x=mouseX;dragObject.y=mouseY;}}functionmouseReleased(){dragging=false;dragObject=null;}
<summary>Mouse Event Interactive Demo</summary>
Type: microsim
Learning objective: Demonstrate mousePressed(), mouseDragged(), and mouseReleased() through interactive drawing (Bloom: Apply, Analyze)
Canvas layout:
- Drawing area: 400x350 pixels (acts as drawing canvas)
- Control area: 50 pixels for clear button
Visual elements:
- Blank canvas that users can draw on
- Current mouse position displayed
- Different colors for different actions:
- Blue dots on click (mousePressed)
- Red line while dragging (mouseDragged)
- Green dot on release (mouseReleased)
- Event log showing recent events
Interactive features:
- Click anywhere: Blue dot appears
- Click and drag: Red trail follows cursor
- Release: Green dot marks end
- Event type displayed in corner
Controls:
- Button: "Clear Canvas"
- Toggle: "Show Event Log"
Behavior:
- Drawing persists until cleared
- Event log shows last 5 events
- Position coordinates update in real-time
- Clear demonstration of each event type
Educational annotations:
- "mousePressed() fires once per click"
- "mouseDragged() fires continuously while dragging"
- "mouseX, mouseY always available"
Color scheme:
- Click dots: blue
- Drag trails: red with alpha
- Release dots: green
- Background: white
Implementation: p5.js with mousePressed, mouseDragged, mouseReleased
Click Detection: Is the User Clicking on Something?
A common pattern is detecting if a click hit a specific object:
1 2 3 4 5 6 7 8 91011121314
functionmousePressed(){// Check if click is on the ballletd=dist(mouseX,mouseY,ball.x,ball.y);if(d<ball.radius){ball.selected=true;console.log("Ball clicked!");}// Check if click is on a rectangleif(mouseX>rect.x&&mouseX<rect.x+rect.width&&mouseY>rect.y&&mouseY<rect.y+rect.height){rect.selected=true;}}
Keyboard Events: Keys to Control
Keyboard events provide an alternative input method, great for quick actions, shortcuts, and game-like interactions.
The keyPressed() Function
The keyPressed() function runs once when a key is pressed:
// Arrow keysLEFT_ARROW,RIGHT_ARROW,UP_ARROW,DOWN_ARROW// Modifier keysSHIFT,CONTROL,ALT// Other special keysENTER,RETURN,BACKSPACE,DELETE,ESCAPE,TAB
Keyboard Shortcuts Table
Document keyboard shortcuts for users:
Key
Action
Space
Start/Pause animation
R
Reset simulation
↑↓
Increase/decrease speed
←→
Adjust parameter
Escape
Stop simulation
Event Handlers: The Responders
Event handlers are functions that respond to specific events. In p5.js, there are two types:
Built-in handlers: Predefined function names (mousePressed, keyPressed)
Callback handlers: Functions you assign to DOM elements
Built-in Event Handler Functions
1 2 3 4 5 6 7 8 91011
// Mouse handlersfunctionmousePressed(){}// Click downfunctionmouseReleased(){}// Click upfunctionmouseMoved(){}// Mouse movement (no click)functionmouseDragged(){}// Move while clickingfunctionmouseWheel(event){}// Scroll wheel// Keyboard handlersfunctionkeyPressed(){}// Key downfunctionkeyReleased(){}// Key upfunctionkeyTyped(){}// Character typed
Callback Event Handlers
For DOM elements, you assign callbacks:
1 2 3 4 5 6 7 8 91011121314151617
// Button callbackmyButton.mousePressed(handleButtonClick);myButton.mouseOver(handleHover);myButton.mouseOut(handleLeave);// Slider callbackmySlider.input(handleSliderChange);// Fires while draggingmySlider.changed(handleSliderDone);// Fires when released// The callback functionsfunctionhandleButtonClick(){console.log("Button was clicked!");}functionhandleSliderChange(){console.log("Slider value: "+this.value());}
<summary>Event Handler Flow Diagram</summary>
Type: diagram
Purpose: Show how events flow from user action to handler function (Bloom: Understand)
Layout: Left-to-right flow diagram
Components:
1. User Action (left side):
- Mouse click icon
- Keyboard icon
- Slider icon
2. Event Detection (middle):
- "p5.js Event System" box
- Arrows showing event routing
3. Event Handlers (right side):
- mousePressed() function box
- keyPressed() function box
- slider.input() callback box
4. Response (far right):
- State changes
- Visual updates
- Animation control
Flow arrows:
- User clicks → mousePressed() → update state
- User types → keyPressed() → update state
- User drags slider → input callback → parameter change
Visual style:
- Rounded boxes for functions
- Arrows showing data flow
- Color coding by event type
Annotations:
- "Built-in handlers have special names"
- "Callbacks are assigned to elements"
- "State changes trigger visual updates in draw()"
Color scheme:
- Mouse events: blue
- Keyboard events: green
- DOM events: orange
- State/response: purple
Implementation: Mermaid.js or static SVG
User Interaction: Designing for Humans
User interaction encompasses all the ways users engage with your MicroSim. Good interaction design makes simulations intuitive and enjoyable.
Interaction Design Principles
Immediate feedback: Every action should produce visible results
Consistent behavior: Similar controls should work similarly
Clear affordances: Controls should look interactive
Error prevention: Make it hard to do the wrong thing
Forgiving design: Easy to undo or reset
Providing Feedback
Users need to know their actions had effect:
1 2 3 4 5 6 7 8 910111213141516
functiondraw(){// Visual feedback for button hoverif(isHovering){cursor(HAND);}else{cursor(ARROW);}// Visual feedback for slider adjustmentif(speedChanged){// Briefly highlight the affected elementfill(255,255,0,fadeAmount);rect(ball.x-5,ball.y-5,30,30);fadeAmount-=5;}}
The isRunning State Pattern
The isRunning state is a boolean variable that controls whether your animation is active. This simple pattern is essential for playable, pauseable simulations.
Basic isRunning Pattern
1 2 3 4 5 6 7 8 910111213141516171819
letisRunning=false;functiondraw(){background(240,248,255);// Only update physics when runningif(isRunning){updatePhysics();}// Always draw current statedrawVisualization();drawControls();}functiontoggleRunning(){isRunning=!isRunning;startButton.html(isRunning?'Pause':'Start');}
Extended State Pattern
For more complex simulations, use multiple state variables:
letisRunning=false;letisPaused=false;letstartButton,pauseButton,resetButton;functionsetup(){createCanvas(400,450);startButton=createButton('Start');startButton.position(20,410);startButton.mousePressed(toggleStart);pauseButton=createButton('Pause');pauseButton.position(100,410);pauseButton.mousePressed(togglePause);pauseButton.attribute('disabled','');// Disabled until startedresetButton=createButton('Reset');resetButton.position(180,410);resetButton.mousePressed(resetAll);}functiontoggleStart(){isRunning=!isRunning;isPaused=false;if(isRunning){startButton.html('Stop');pauseButton.removeAttribute('disabled');}else{startButton.html('Start');pauseButton.attribute('disabled','');pauseButton.html('Pause');}}functiontogglePause(){if(isRunning){isPaused=!isPaused;pauseButton.html(isPaused?'Resume':'Pause');}}functionresetAll(){isRunning=false;isPaused=false;// Reset all simulation variablesinitializeSimulation();// Reset UIstartButton.html('Start');pauseButton.html('Pause');pauseButton.attribute('disabled','');}functiondraw(){background(240,248,255);if(isRunning&&!isPaused){updateSimulation();}drawSimulation();drawControlRegion();}
<summary>Animation Control Panel Demo</summary>
Type: microsim
Learning objective: Demonstrate the complete start/stop/pause/reset pattern with a simple animation (Bloom: Apply, Analyze)
Canvas layout:
- Drawing area: 400x350 pixels
- Control area: 50 pixels for buttons
Visual elements:
- Bouncing ball animation
- Current state indicator (Running/Paused/Stopped)
- Frame counter showing animation progress
- Button row with all four controls
Buttons:
- Start/Stop toggle button (changes label based on state)
- Pause/Resume toggle button (disabled when stopped)
- Reset button (always enabled)
- State indicator text
State visualization:
- Green glow when running
- Yellow glow when paused
- Gray when stopped
- Clear state label
Behavior:
- Start: Ball begins bouncing
- Stop: Ball stops and resets to center
- Pause: Ball freezes in current position
- Resume: Ball continues from paused position
- Reset: Ball returns to center, all values reset
Transitions:
- Stopped → Running (Start)
- Running → Stopped (Stop)
- Running → Paused (Pause)
- Paused → Running (Resume)
- Any → Stopped (Reset)
Educational emphasis:
- Clear state visualization
- Button label changes reflect current state
- Disabled states prevent invalid actions
Implementation: p5.js with isRunning, isPaused pattern
Speed Control: From Slow Motion to Fast Forward
Speed control lets users adjust how fast the simulation runs. This is invaluable for understanding complex dynamics—slow down to see details, speed up to see patterns.
Speed Multiplier Pattern
1 2 3 4 5 6 7 8 91011121314151617
letspeedSlider;letbaseSpeed=2;functionsetup(){speedSlider=createSlider(0.1,3,1,0.1);// 0.1x to 3x speedspeedSlider.position(100,drawHeight+15);}functiondraw(){if(isRunning){letspeedMultiplier=speedSlider.value();letactualSpeed=baseSpeed*speedMultiplier;ball.x+=ball.vx*actualSpeed;ball.y+=ball.vy*actualSpeed;}}
Frame-Independent Speed
For consistent physics regardless of frame rate:
1 2 3 4 5 6 7 8 910111213
letlastTime=0;functiondraw(){letcurrentTime=millis();letdeltaTime=(currentTime-lastTime)/1000;// SecondslastTime=currentTime;if(isRunning){letspeedMultiplier=speedSlider.value();ball.x+=ball.vx*speedMultiplier*deltaTime*60;// Normalize to 60fpsball.y+=ball.vy*speedMultiplier*deltaTime*60;}}
// Complete Control System ExampleletcanvasWidth=400;letdrawHeight=300;letcontrolHeight=100;letcanvasHeight=drawHeight+controlHeight;// Simulation stateletisRunning=false;letisPaused=false;letball={x:200,y:150,vx:3,vy:0};// ControlsletstartButton,pauseButton,resetButton;letspeedSlider,gravitySlider;functionsetup(){createCanvas(canvasWidth,canvasHeight);// ButtonsstartButton=createButton('Start');startButton.position(20,drawHeight+10);startButton.mousePressed(toggleStart);pauseButton=createButton('Pause');pauseButton.position(80,drawHeight+10);pauseButton.mousePressed(togglePause);pauseButton.attribute('disabled','');resetButton=createButton('Reset');resetButton.position(150,drawHeight+10);resetButton.mousePressed(resetAll);// SlidersspeedSlider=createSlider(0.1,3,1,0.1);speedSlider.position(80,drawHeight+45);speedSlider.size(120);gravitySlider=createSlider(0,1,0.3,0.05);gravitySlider.position(280,drawHeight+45);gravitySlider.size(100);describe('Bouncing ball with complete animation controls');}functiontoggleStart(){isRunning=!isRunning;isPaused=false;updateButtonStates();}functiontogglePause(){if(isRunning){isPaused=!isPaused;pauseButton.html(isPaused?'Resume':'Pause');}}functionresetAll(){isRunning=false;isPaused=false;ball={x:200,y:150,vx:3,vy:0};speedSlider.value(1);gravitySlider.value(0.3);updateButtonStates();}functionupdateButtonStates(){startButton.html(isRunning?'Stop':'Start');pauseButton.html('Pause');if(isRunning){pauseButton.removeAttribute('disabled');}else{pauseButton.attribute('disabled','');}}functiondraw(){// Drawing regionbackground(240,248,255);// Update physics if runningif(isRunning&&!isPaused){letspeed=speedSlider.value();letgravity=gravitySlider.value();ball.vy+=gravity*speed;ball.x+=ball.vx*speed;ball.y+=ball.vy*speed;// Bounce off wallsif(ball.x<20||ball.x>canvasWidth-20){ball.vx*=-1;ball.x=constrain(ball.x,20,canvasWidth-20);}if(ball.y>drawHeight-20){ball.vy*=-0.8;ball.y=drawHeight-20;if(abs(ball.vy)<0.5)ball.vy=0;}}// Draw ballfill(100,150,255);stroke(50,100,200);strokeWeight(2);circle(ball.x,ball.y,40);// Control regionfill(255);noStroke();rect(0,drawHeight,canvasWidth,controlHeight);stroke(200);line(0,drawHeight,canvasWidth,drawHeight);// Labelsfill(0);noStroke();textSize(12);textAlign(LEFT,CENTER);text("Speed:",20,drawHeight+55);text("Gravity:",220,drawHeight+55);// State indicatortextAlign(RIGHT,TOP);if(isRunning&&!isPaused){fill(0,150,0);text("▶ Running",canvasWidth-10,drawHeight+10);}elseif(isPaused){fill(200,150,0);text("⏸ Paused",canvasWidth-10,drawHeight+10);}else{fill(100);text("⏹ Stopped",canvasWidth-10,drawHeight+10);}}// Keyboard shortcutsfunctionkeyPressed(){if(key===' '){if(isRunning){togglePause();}else{toggleStart();}}if(key==='r'||key==='R'){resetAll();}}// Click to reposition ballfunctionmousePressed(){if(mouseY<drawHeight){ball.x=mouseX;ball.y=mouseY;ball.vx=random(-3,3);ball.vy=0;}}
Key Takeaways
You've now mastered the controls that put users in control! Here are the essential insights:
Slider controls (createSlider()) handle continuous values with min, max, default, and step parameters.
Button controls (createButton()) trigger discrete actions with callback functions.
The control button family (Start, Stop, Pause, Reset) provides complete animation control.
Mouse events (mousePressed(), mouseDragged()) enable direct canvas interaction.
Keyboard events (keyPressed()) provide shortcuts and alternative input.
Event handlers respond to user actions—both built-in and callback-based.
User interaction design prioritizes feedback, consistency, and forgiveness.
The isRunning state pattern controls animation with a simple boolean.
Animation control combines state management with button interactions.
Speed control uses multipliers to adjust simulation pace.
Parameter adjustment lets users tune simulation behavior with sliders.
Input handling unifies all input sources into a coherent control system.
Challenge: Add a keyboard shortcut
Take one of your existing MicroSims and add keyboard shortcuts for common actions. Use spacebar for start/pause, 'R' for reset, and arrow keys for parameter adjustment. How does this improve the user experience?
Next Steps
You're now in complete control of user controls! Your MicroSims can respond to sliders, buttons, mouse clicks, and keyboard shortcuts. In the next chapter, we'll explore physics and motion—making objects move realistically with gravity, bouncing, and more.
Remember: good controls should be invisible. When users stop thinking about how to interact and start focusing on what they're learning, you've mastered the art of control.