Make a game for the phone in your hand.
One script reads the Wand like a gamepad: aim, orientation, swing speed, buttons. A single HTML file is a game.
hello/index.html33 lines, the whole game
<!doctype html>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hello, Wand</title>
<style>html,body{margin:0;height:100%;background:#0a0b0d;overflow:hidden}canvas{display:block}</style>
<canvas id="c"></canvas>
<script src="../lib/mimic.js"></script>
<script>
const mc = new MimicController(); // the phone if one is paired, the mouse if not
const cv = document.getElementById('c'), ctx = cv.getContext('2d');
const spawn = () => ({ x: Math.random() * 1.4 - 0.7, y: Math.random() * 1.0 - 0.5 });
let target = spawn(), score = 0, flash = 0;
addEventListener('keydown', e => { if (e.key === 'r') mc.enableRumble(); }); // Chrome asks once
function frame() {
mc.update(); // read the phone once per frame
cv.width = innerWidth; cv.height = innerHeight;
const c = v => Math.max(-1, Math.min(1, v)); // keep it on screen
const px = p => [(c(p.x) + 1) / 2 * cv.width, (1 - c(p.y)) / 2 * cv.height];
const [tx, ty] = px(target), [ax, ay] = px(mc.pointer); // where the phone points
if (Math.hypot(ax - tx, ay - ty) < 70 && mc.angularSpeed > 5) { // a real swing, not a nudge
score++; flash = 1; target = spawn();
mc.rumble(0.8, 60); // the phone kicks (after R was pressed)
}
ctx.fillStyle = `rgba(255,180,84,${0.3 + flash})`; flash *= 0.9;
ctx.beginPath(); ctx.arc(tx, ty, 54, 0, 7); ctx.fill();
ctx.fillStyle = mc.isDown('a') ? '#ff6b4a' : '#5ee6d0'; // hold A (or click) to change colour
ctx.beginPath(); ctx.arc(ax, ay, 12, 0, 7); ctx.fill();
ctx.fillStyle = '#e8eaee'; ctx.font = '20px system-ui';
ctx.fillText(`Swing through the orange circle. Score ${score}. Input: ${mc.source}`, 24, 40);
requestAnimationFrame(frame);
}
frame();
</script>What mimic.js gives you.
mc.pointerWhere it points, -1 to 1
mc.quatFull 3D orientation
mc.angularSpeedA nudge or a swing
mc.linearAccelThrusts, stabs, throws
mc.rumble()Make the phone kick
mc.sourceMouse stands in without a phone
MimicController.all()Up to four phones
Every value, in three.js axes: the full reference.
Make it play well.
1
Design for one button
In Grip only the volume keys reach. Never need more.
2
Menus by pointing
lib/wandcursor.js: point at a button, press A.
3
Keep the mouse in
People try it before they install anything.
4
Four phones, one screen
Each phone is its own controller.