npm.io
0.2.1 • Published 3 weeks ago

screenframe3d

Licence
MIT
Version
0.2.1
Deps
0
Size
5.5 MB
Vulns
0
Weekly
0

Screenframe3D

Composite an app screenshot onto a real 3D phone. Live demo.

Phone GLBs are not included in the npm package (Sketchfab licenses). You download a model once, drop it in public/models/, and Screenframe does the rest. First-party devices are planned.

Install

npm install screenframe3d three

React apps also need react / react-dom. Vite apps should add the plugin below so the HDRI (and later, posters) land automatically.

1. Get a device model from Sketchfab

device is a path. Screenframe loads /models/{device}.glb from your site.

Device device id Put the file at Sketchfab
iPhone 5s apple/iphone-5s public/models/apple/iphone-5s.glb IPhone 5s by Eternal Realm (CC-BY-4.0)
iPhone 12 Pro apple/iphone-12-pro public/models/apple/iphone-12-pro.glb iPhone 12 Pro by DatSketch (CC-BY-4.0)
iPhone 14 Pro apple/iphone-14-pro public/models/apple/iphone-14-pro.glb No single listing is embedded in the file. Search downloadable iPhone 14 Pro models. You want a body_mat (or similar) whose emissive map includes a bright portrait screen.
iPhone 17 Pro apple/iphone-17-pro public/models/apple/iphone-17-pro.glb Iphone 17 pro by Ibrahim.Bhl (CC-BY-4.0)
Download steps
  1. Make a free Sketchfab account.
  2. Open the model. Confirm it is downloadable and that the license fits your project (CC-BY requires credit).
  3. Download 3D model → glTF (or GLB if offered).
  4. If you get a folder, use the .glb (often scene.glb). If you only get scene.gltf + scene.bin + textures/, keep that folder structure or convert to a single .glb.
  5. Rename / move it to the path in the table. The filename must match device exactly: apple/iphone-12-pro → models/apple/iphone-12-pro.glb.
What Screenframe looks for on the glass

Any downloadable phone can work if Screenframe can find the display:

  • A material or mesh named screen, wallpaper, Screen_BG, display, or lcd, or
  • A material named body_mat whose emissive map has a bright portrait rectangle (atlas).

The four rows above are the combinations this repo is tested against. Catalog in code: DEVICES from screenframe3d.

2. Environment map (glass and metal)

Reflections use /env/greenwich_park_1k.hdr by default (Greenwich Park, CC0, Poly Haven). Omit environment to keep that map.

Pass environment as a preset id or any HDR URL:

environment File Source
greenwich-park (default) /env/greenwich_park_1k.hdr Greenwich Park
studio /env/studio_small_08_1k.hdr Studio Small 08
sunset /env/venice_sunset_1k.hdr Venice Sunset

The Vite plugin copies those HDRIs into public/env/ when they are missing. Without the plugin, copy them from node_modules/screenframe3d/assets/env/ or download the 1K HDRs from Poly Haven.

Key light is a close area light (so metal picks up a broad highlight, not a pin-prick). The HDRI rotates so its brightest region sits with that light. Omit light to keep direction (4, 6, 5), intensity 0.22, and color #fff2e0.

initDeviceShowcase({
  container,
  screenshot: '/screenshot.png',
  device: 'apple/iphone-12-pro',
  environment: 'studio',
  light: {
    direction: { x: 4, y: 6, z: 5 },
    intensity: 0.22, // `amplitude` is an alias
    envIntensity: 1.8, // `envStrength` is an alias
    color: '#fff2e0',
  },
});

After load, setEnvironment(idOrUrl) and setLight({ ... }) update the live scene without recreating it.

import { defineConfig } from 'vite';
import { screenframe } from 'screenframe3d/vite';

export default defineConfig({
  plugins: [screenframe()],
});

That plugin:

  • Copies bundled HDRIs into public/env/
  • Writes extracted device textures to public/textures/ on first run
  • Captures a still (poster) so the next load can show an image before WebGL is ready

It does not download Sketchfab models.

4. Use it

Vanilla
<div id="device"></div>
<script type="module">
  import { initDeviceShowcase } from 'screenframe3d';

  initDeviceShowcase({
    container: document.getElementById('device'),
    screenshot: '/screenshot.png',
    device: 'apple/iphone-12-pro',
    publicBase: import.meta.env.BASE_URL,
  });
</script>
React
import { DeviceShowcase } from 'screenframe3d/react';

<DeviceShowcase
  screenshot="/screenshot.png"
  device="apple/iphone-12-pro"
  publicBase={import.meta.env.BASE_URL}
/>

publicBase matters if the app is not served from / (GitHub Pages, a Vite base, etc.).

Options

Passed to initDeviceShowcase() or <DeviceShowcase />:

Option Description
container DOM node for the canvas (vanilla only)
screenshot URL of the image on the glass (not downscaled)
device Path id, e.g. apple/iphone-12-pro → /models/apple/iphone-12-pro.glb
publicBase Prefix for models, env, posters, textures
environment Preset id (greenwich-park, studio, sunset) or HDR URL. Default Greenwich Park.
light Direction, intensity (amplitude alias), color, and env strength (envIntensity / envStrength). HDRI follows the key light.
fov, zoom, baseTilt Camera / rest pose
tiltEnabled, spring, scrollTilt Pointer and scroll motion
poster false / omit = no still. true / 'auto' = hashed /posters/...webp. Or pass a URL.
cachePoster, cacheDeviceTextures Persist stills and maps during vite dev (needs the plugin)
fallbackCondition, fallbackImage Opt-in static image instead of WebGL

Development (this repo)

npm install
npm run dev      # landing + playground (models already in public/)
npm run build    # library → dist/

Phone GLBs in public/models/ are for the demo only. They are not published to npm.

License

MIT for the library code.

Device models you download remain under their Sketchfab licenses; CC-BY models need attribution. Bundled HDRIs are CC0 (Poly Haven).

Keywords