@4ndr3.dk/mophree-engine
v0.2.6
Published
Framework-free three.js engine — procedural, photoreal iPhone/iPad device models with a camera rig, keyframe/easing timeline, and video export. Developed during the Config Makeathon 2026 as the 3D engine behind the mophree Figma Make project.
Downloads
1,398
Maintainers
Readme
mophree-engine
Framework-free three.js engine — procedural, photoreal iPhone / iPad device models with a camera rig, a keyframe + cubic-bezier easing timeline, and real-time video export (WebM / MP4, with alpha).
This package was developed during the Config Makeathon 2026 as the 3D engine
behind the mophree Figma Make project. The editor UI is built in Figma Make;
this package is the rendering/animation core it imports — the way you'd pull in
any library. Every module imports only three, with no app framework, no build
step, and no binary 3D assets (the device geometry is generated in code from
Apple's published dimensional drawings).
Install
npm install @4ndr3.dk/mophree-engine threethree is a peer dependency on purpose: the host app and this package must
resolve to a single three instance. scene.js patches the global
THREE.ShaderChunk (to add distance-based PCSS contact shadows) and relies on
shared three internals — two copies would silently break shadows and
instanceof checks. Pinned to the 0.180.x line the engine was built against.
Usage
import { createStage, createRig, createIphone17, TL } from '@4ndr3.dk/mophree-engine';
const stage = createStage(document.getElementById('viewport')); // appends a <canvas>
const rig = createRig(stage.camera, stage.renderer.domElement);
const device = createIphone17();
stage.scene.add(device.group);
rig.setDefaults(device.camDefaults, true);
stage.setSize(1280, 720); // letterbox to taste
// choreograph a camera move
const tl = TL.createTimeline({ duration: 6, preset: 'orbit' });
TL.regeneratePreset(tl, device.camDefaults);
let t = 0, last = performance.now();
function frame(now) {
requestAnimationFrame(frame);
t = (t + (now - last) / 1000) % tl.duration; last = now;
const pose = TL.evaluate(tl, t);
if (pose) rig.setPose(pose, true);
rig.update(1 / 60);
stage.render();
}
requestAnimationFrame(frame);React adapter (/react)
In React (e.g. a Figma Make project), import the headless useMophree hook from
the /react subpath instead of wiring the engine by hand. It owns the
stage/rig/devices/timeline and the render loop and returns
{ hostRef, state, actions } — attach hostRef to a div, build your UI against
actions/state:
import { useMophree, SCENES, ASPECTS } from '@4ndr3.dk/mophree-engine/react';
export default function Editor() {
const { hostRef, state, actions } = useMophree();
return (
<>
<button onClick={() => actions.toggle()}>{state.playing ? 'Pause' : 'Play'}</button>
<div ref={hostRef} style={{ width: '100%', height: 480 }} />
</>
);
}react is an optional peer dependency — needed only if you import /react.
The core entry (.) stays framework-free (three.js only).
API
createStage(el)→{ renderer, scene, camera, setSize(w,h), render(), setScene(name), setAmbient(hex), getScene() }. Scenes:color | black | white | transparent. Importing this applies the PCSS shader patch once.createRig(camera, domElement)→{ setPose, setDefaults, update, getTarget, getCurrent, getTargetY, isDragging, onUserChange, dispose }— orbit camera (yaw/pitch/dist) with damping + drag/wheel input.createIphone17()/createIpad()→ device contract{ id, label, group, baseY, bob, screen:{mesh,w,h,defaultMat}, camDefaults:{dist,targetY,pitch}, finishes:[{name,hex}], setFinish(hex) }.TL(namespace, pure data) —createTimeline, addKeyframe, moveKeyframe, removeKeyframe, getKeyframe, evaluate, setKeyframeEasing, setKeyframeBezier, setDuration, adoptVideoDuration, regeneratePreset, defaultTabs, bezierEase, EASINGS, PRESETS, ….Media(namespace) —loadVideoBlob, applyToScreen, createWallpaperMaterial, coverFit, makeTestClip, …(video →VideoTexture, with the Infinity-duration fix and cover-fit).exportVideo({ canvas, duration, format, prepare, tick, restore, onProgress }),FORMATS,supportedFormats(),resolveMime(),downloadBlob()— real-timecaptureStream+MediaRecordercapture; WebM preserves alpha.DEFAULT_AMBIENT— the default ambient tint hex.
Attribution
- Built on three.js (MIT).
- Device geometry is reconstructed from Apple's published dimensional drawings used as geometric reference only — no Apple assets are included or distributed.
License
MIT — see LICENSE.
