npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

screenframe3d

v0.2.1

Published

3D iPhone mockups for landing pages. Put an app screenshot on a real device with React, Vite, and three.js.

Downloads

704

Readme

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.

3. Vite plugin (recommended)

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).