Load three-phone as a plain script, load three.js with an import map, then a tiny loader makes THREE global and runs your sketch. Lock gestures and enable the capability your sketch needs from a user tap.
The three-phone + three.js head
<!-- three-phone: plain script, window globals -->
<script src="https://cdn.jsdelivr.net/npm/three-phone@0.1.0/dist/three-phone.min.js"></script>
<!-- three.js via import map -->
<script type="importmap">
{ "imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.185.1/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.185.1/examples/jsm/" } }
</script>
<!-- loader: expose THREE, then run sketch.js (a plain script) -->
<script type="module">
import * as THREE from 'three';
window.THREE = THREE;
const s = document.createElement('script');
s.src = 'sketch.js';
document.body.appendChild(s);
</script>
// sketch.js
let renderer, scene, camera, cube;
function init() {
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 100);
camera.position.z = 5;
scene.add(new THREE.HemisphereLight(0xffffff, 0x222233, 1));
cube = new THREE.Mesh(new THREE.BoxGeometry(1.6, 2.6, 0.3),
new THREE.MeshStandardMaterial({ color: 0x8b5cf6 }));
scene.add(cube);
showDebug();
setPhoneCanvas(renderer);
enableGyroTap('Tap to enable motion sensors');
lockGestures();
animate();
}
function animate() {
requestAnimationFrame(animate);
if (window.sensorsEnabled) applyDeviceRotation(cube, { smooth: 0.8 });
else cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
init();
Permission pattern: put code that uses phone hardware inside a positive enabled check — if (window.sensorsEnabled) { ... }, if (window.micEnabled) { ... }, or the matching status flag for the capability you enabled.
Motion Sensors
if (window.sensorsEnabled) {
applyDeviceRotation(mesh, { smooth: 0.8 });
}
Touch Picking
function touchStarted() {
const rc = getTouchRaycaster(mouseX, mouseY, camera);
const hit = rc.intersectObjects(meshes)[0];
if (hit) hit.object.material.color.set(0x8b5cf6);
}
Script order matters: load three-phone.js first, then the import map, then the loader module. The loader sets window.THREE before it injects sketch.js, so your sketch can use the global THREE without being a module.
Tooling
Agent Skills
An optional skill teaches AI coding assistants how three-phone works, so generated sketches use the right permission flow, motion globals, and three.js helpers. See SKILL.md.
three-phone
Knowledge of the library API, the permission model, the motion/touch globals, and the three.js integration helpers (applyDeviceRotation, getTouchRaycaster, PhoneCamera).
p5-phone
Building the same ideas with p5.js instead of three.js? The p5-phone library shares this exact permission API.
Reference
API
Grouped by the job you are doing. The permission table keeps the five UI styles visible; each category lists the three-phone functions and the three.js APIs they pair with.
Examples
Example Catalog
Each example is a self-contained three.js sketch designed to show off 3D — lighting, materials, shadows, raycasting, spatial audio. Every card links to its source and, where one exists, its p5.js twin. Scan the QR to open on a phone.
Support
Compatibility
Plan mobile sketches by platform first. Browser permissions and hardware support matter more than the three.js version for most phone behavior.
iOS Safari
Motion sensors, microphone, sound, speech, and camera must start from a user tap or button.
Motion permission uses Apple-specific sensor prompts, so the enable helpers are important.
Web NFC, torch, and vibration are not available in Safari on iPhone.
Video textures need playsinline muted and a post-gesture play() — PhoneCamera handles this.
Android Chrome
Motion sensors usually work without the iOS-style sensor permission prompt.
Microphone, sound, speech, and camera still need a user gesture and browser permission.
Web NFC, torch, and vibration are Android Chrome features (NFC/BLE require HTTPS).
Web Bluetooth works in Chrome/Edge; on iOS use the Bluefy browser.
Capability
iOS Safari
Android Chrome
Desktop browsers
three.js / WebGL
Supported.
Supported.
Supported.
Motion sensors
Supported after a tap permission flow.
Supported; permission request is usually a no-op.
Limited or unavailable on most laptops and desktops.
Touch / picking
Supported through pointer events.
Supported through pointer events.
Use the mouse for testing (touches has one entry).