import scene3d
scene = scene3d.Scene()
scene.set_sky('#1a1a2e')
scene.set_ground(length=10, width=10)
sphere = scene3d.Shapes.Sphere(diameter=1.5, segments=16)
sphere.set_color('#4488ff')
sphere.set_position(0, 0.75, 0)
scene.add(sphere)
colors = ['#4488ff', '#e94560', '#f5a623', '#44cc88', '#cc44ff']
idx = 0
def next_color():
global idx
idx = (idx + 1) % len(colors)
sphere.set_color(colors[idx])
scene.on_key(scene3d.Key.SPACE, next_color)
ctx = scene.get_context('2d')
ctx.fill_style = '#ffffff'
ctx.font = '18px sans-serif'
ctx.fill_text('Press SPACE to change color', 10, 30)
scene.run()On Key — Keyboard Events
You already know how to respond to a mouse click with on_click. Keyboard events work the same way: you write a function and register it with scene.on_key(), and that function runs every time the key is pressed.
Keyboard input is how most games let the player control a character — arrow keys to move, spacebar to jump or fire, letter keys for actions.
Your First Key Handler
The pattern is identical to on_click: write a function, then register it.
def next_color():
sphere.set_color('#ff0000')
scene.on_key(scene3d.Key.SPACE, next_color) # register before scene.run()scene3d.Key.SPACE is a key constant — a named value for the Spacebar. Run the cell and press Space to cycle through colors.
Key Constants and Registration Rules
Use scene3d.Key constants for special keys:
| Constant | Key |
|---|---|
Key.LEFT |
← Arrow |
Key.RIGHT |
→ Arrow |
Key.UP |
↑ Arrow |
Key.DOWN |
↓ Arrow |
Key.SPACE |
Spacebar |
Key.ENTER |
Enter |
Key.ESCAPE |
Esc |
For letter keys, pass a plain string: scene.on_key('w', fn).
The registration rules are the same as on_click and on_collide: - Register after meshes are added to the scene - Register before scene.run() - The canvas is auto-focused — keys respond immediately, no clicking needed
{ “question_type”: “true_false”, “question”: “You need to click on the scene canvas before keyboard events will work.”, “answer”: “False”, “submitted_answer”: “” }
Moving with Arrow Keys
The most common use of on_key is player movement. Each key handler reads the current position with get_position(), adds an offset, then calls set_position() with the new location.
def move_left():
x, y, z = player.get_position()
player.set_position(x - STEP, y, z)Note: As soon as you register any
on_keyhandler, the default camera arrow-key controls are automatically removed. Your handlers take over those keys. Mouse orbit and scroll-wheel zoom still work as normal.
Run the cell and use the arrow keys to move the sphere around the grid.
import scene3d
STEP = 1.0
scene = scene3d.Scene()
scene.set_sky('#0f3460')
ground = scene.set_ground(length=16, width=16)
ground.set_material(scene3d.Material.Tiles.Checkerboard)
ground.set_tiling(8)
player = scene3d.Shapes.Sphere(diameter=0.8, segments=16)
player.set_color('#e94560')
player.set_position(0, 0.4, 0)
scene.add(player)
ctx = scene.get_context('2d')
def draw_hud():
x, y, z = player.get_position()
ctx.clear()
ctx.fill_style = '#ffffff'
ctx.font = '18px sans-serif'
ctx.fill_text(f'x = {x:.1f} z = {z:.1f}', 10, 30)
def move(dx, dz):
x, y, z = player.get_position()
player.set_position(x + dx, y, z + dz)
draw_hud()
scene.on_key(scene3d.Key.LEFT, lambda: move(-STEP, 0))
scene.on_key(scene3d.Key.RIGHT, lambda: move( STEP, 0))
scene.on_key(scene3d.Key.UP, lambda: move(0, STEP))
scene.on_key(scene3d.Key.DOWN, lambda: move(0, -STEP))
draw_hud()
scene.run(){ “question_type”: “multiple_choice”, “question”: “When you register any on_key handler, what happens to the default camera arrow-key controls?”, “options”: [ { “key”: “a”, “text”: “They still work alongside your handlers” }, { “key”: “b”, “text”: “They are automatically disabled” }, { “key”: “c”, “text”: “They only work when Shift is held” }, { “key”: “d”, “text”: “Mouse orbit is also disabled” } ], “answer”: “b”, “submitted_answer”: “” }
Letter Keys
For letter keys, pass a plain lowercase string instead of a Key constant:
scene.on_key('w', move_forward) # the W key
scene.on_key('a', move_left)
scene.on_key('s', move_back)
scene.on_key('d', move_right)WASD is the standard layout in PC games — left hand on the keyboard, right hand on the mouse. You can mix letter keys and Key constants freely in the same scene.
The scene below uses WASD to move and SPACE to cycle through colors. Try both controls at once.
import scene3d
STEP = 1.0
scene = scene3d.Scene()
scene.set_sky('#1a1a2e')
ground = scene.set_ground(length=18, width=18)
ground.set_material(scene3d.Material.Tiles.Checkerboard)
ground.set_tiling(9)
player = scene3d.Shapes.Sphere(diameter=0.8, segments=16)
player.set_color('#f5a623')
player.set_position(0, 0.4, 0)
scene.add(player)
colors = ['#f5a623', '#e94560', '#4488ff', '#44cc88', '#cc44ff']
color_idx = 0
def move(dx, dz):
x, y, z = player.get_position()
player.set_position(x + dx, y, z + dz)
def cycle_color():
global color_idx
color_idx = (color_idx + 1) % len(colors)
player.set_color(colors[color_idx])
scene.on_key('a', lambda: move(-STEP, 0))
scene.on_key('d', lambda: move( STEP, 0))
scene.on_key('w', lambda: move(0, STEP))
scene.on_key('s', lambda: move(0, -STEP))
scene.on_key(scene3d.Key.SPACE, cycle_color)
ctx = scene.get_context('2d')
ctx.fill_style = '#aaaaaa'
ctx.font = '15px sans-serif'
ctx.fill_text('W/A/S/D to move SPACE to change color', 10, 30)
scene.run(){ “question_type”: “multiple_choice”, “question”: “How do you register a handler for the letter ‘w’ key?”, “options”: [ { “key”: “a”, “text”: “scene.on_key(scene3d.Key.W, fn)” }, { “key”: “b”, “text”: “scene.on_key(Key.LETTER_W, fn)” }, { “key”: “c”, “text”: “scene.on_key(‘w’, fn)” }, { “key”: “d”, “text”: “scene.on_key(87, fn)” } ], “answer”: “c”, “submitted_answer”: “” }
{ “question_type”: “true_false”, “question”: “A scene can have both arrow key handlers (Key.LEFT etc.) and letter key handlers (‘a’, ‘w’ etc.) registered at the same time.”, “answer”: “True”, “submitted_answer”: “” }
Try It Yourself
Navigate the red sphere to reach the gold sphere. Both WASD and arrow keys are registered — use whichever feels natural.
Use the slider to change how far the sphere moves with each keypress.
import scene3d
STEP = 1.0 #@param {type:"slider", min:0.5, max:2.0, step:0.5}
scene = scene3d.Scene()
scene.set_sky('#0f3460')
ground = scene.set_ground(length=22, width=22)
ground.set_material(scene3d.Material.Tiles.Checkerboard)
ground.set_tiling(11)
player = scene3d.Shapes.Sphere(diameter=0.8, segments=16)
player.set_color('#e94560')
player.set_position(-6, 0.4, -6)
scene.add(player)
goal = scene3d.Shapes.Sphere(diameter=0.9, segments=16)
goal.set_color('#f5a623')
goal.set_position(6, 0.45, 6)
scene.add(goal)
ctx = scene.get_context('2d')
found = False
def draw_hud():
ctx.clear()
ctx.fill_style = '#ffffff'
ctx.font = '18px sans-serif'
ctx.fill_text('Reach the gold sphere! — W/A/S/D or arrow keys', 10, 30)
if found:
ctx.fill_style = '#f5a623'
ctx.font = '24px sans-serif'
ctx.fill_text('You made it!', 10, 62)
def check_goal():
global found
if found:
return
px, _, pz = player.get_position()
gx, _, gz = goal.get_position()
if abs(px - gx) <= STEP and abs(pz - gz) <= STEP:
found = True
player.set_color('#f5a623')
def move(dx, dz):
x, y, z = player.get_position()
player.set_position(x + dx, y, z + dz)
check_goal()
draw_hud()
scene.on_key('a', lambda: move(-STEP, 0))
scene.on_key('d', lambda: move( STEP, 0))
scene.on_key('w', lambda: move(0, STEP))
scene.on_key('s', lambda: move(0, -STEP))
scene.on_key(scene3d.Key.LEFT, lambda: move(-STEP, 0))
scene.on_key(scene3d.Key.RIGHT, lambda: move( STEP, 0))
scene.on_key(scene3d.Key.UP, lambda: move(0, STEP))
scene.on_key(scene3d.Key.DOWN, lambda: move(0, -STEP))
draw_hud()
scene.run()Think about a game or interactive experience you’d like to build using keyboard controls.
Which keys would you use? Would you use arrow keys, WASD, or both? What would each key do — move a character, trigger an action, change something in the scene? Describe the experience and sketch out which on_key registrations you’d need.