react-iron-man
Non-commercialIron Man flies around your React site, heckles your visitors, and plays catch with their real hand through the webcam. One component, one line.
This page is the demo.
He's already here, in the margin. Move your cursor and he watches it; point at a link and he'll have something to say; scroll fast and he gets left behind. Click him to start a game of catch, allow the camera, and pinch your fingers right on him to grab. Press Esc to stop. For Batman, find the faint bat in the footer.
Install
npm i react-iron-manUse
Render it once, anywhere on the page. It positions itself, so where it sits in your tree doesn't matter.
import { Heroes } from "react-iron-man";
export default function Layout({ children }) {
return (
<>
{children}
<Heroes />
</>
);
}In Next.js, put it in your root layout so he stays across pages:
// app/layout.tsx: it's already a client component, so a Server layout can render it.
import { Heroes } from "react-iron-man";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Heroes contentWidth={720} />
<p>Iron Man by Grant Riley (CC BY-NC)</p>
</body>
</html>
);
}Batman is opt-in. Hide a switch somewhere for visitors to find:
const [batman, setBatman] = useState(false);
<button onClick={() => setBatman((b) => !b)}>Summon Batman</button>
<Heroes batman={batman} />Props
| Prop | Type | Default | What it does |
|---|---|---|---|
batman | boolean | false | Batman joins Iron Man while true. They banter, swap sides, and he can be chased too. |
models | { ironMan?: string; batman?: string } | jsDelivr | URLs of self-hosted .glb models, instead of loading them from the CDN. |
contentWidth | number | 900 | Width of your page's centred content column, in px. They keep to the empty margins beside it. |
Dark mode follows a .dark or [data-theme="dark"] class on any ancestor, usually <html>.
What your visitors get
- Lives in your page's side margin, bobbing on his thrusters, and turns to watch the cursor.
- Heckles whatever the visitor points at: links, GitHub, LinkedIn, email links, images, buttons.
- Gets left behind when you scroll, then flies back to his spot. Complains if you scroll too fast.
- Swaps sides of the page every so often and talks when things are quiet.
- Poke him and the page becomes a game of catch: he dodges, barrel-rolls, and overheats after five dodges in a row. That's your window.
- Only a real hand can catch him. The webcam tracks it in the browser; pinch right on him to grab, let go to throw him.
Requirements
- React 18 or newer
- Any React setup: Next.js (App or Pages Router), Vite, Remix, Astro islands. No Tailwind or CSS import needed; it brings its own styles.
- A browser with WebGL
- Every current desktop browser. Best on wide screens, where he has a margin to live in; on phones he keeps to the edge.
- HTTPS, for the game
- Browsers only give camera access on HTTPS pages (and localhost). Without a camera he still flies, talks and dodges; he just can't be caught.
- About 1 MB on page load
- Iron Man's model (1.0 MB) loads in the background after the page. Batman (0.3 MB) loads only when summoned.
- About 11 MB on the first poke
- The hand tracker: the MediaPipe runtime (3 MB compressed, from jsDelivr) and its hand model (7.8 MB, from Google). Loaded only when someone starts the game, then cached.
- A CSP that allows it
- If your site sets a Content Security Policy, allow
cdn.jsdelivr.netandstorage.googleapis.cominconnect-srcandscript-src, plus'wasm-unsafe-eval'. - Room at z-index 40–60
- He flies above your page at z-index 55 and the game overlay sits at 50–60. Keep modals you need on top above 60.
- Non-commercial use
- The Iron Man model is CC BY-NC: personal sites, portfolios and hobby projects only, with credit. See the license below.
Privacy
Hand tracking runs entirely in the visitor's browser. Camera frames never leave their device and nothing is recorded: the game box shows only an outline of the hand, never the video. The camera turns off the moment the game ends. Visitors who prefer reduced motion get a calmer Iron Man.
Self-host the models
By default the models load from jsDelivr. To serve them from your own domain, copy them out of the package and point models at them:
cp node_modules/react-iron-man/models/*.glb public/models/
<Heroes models={{ ironMan: "/models/iron-man.glb", batman: "/models/batman.glb" }} />License and credits
The code is MIT. The models are not: the Iron Man model by Grant Riley is CC BY-NC 4.0, so non-commercial use only, and the Batman model by LKFisto1707 is CC BY 4.0. Both require credit. Paste this anywhere visible, like your footer:
<a href="https://sketchfab.com/3d-models/iron-man-69dde1ad49e94852984e3d83928efd65">Iron Man</a> by Grant Riley (CC BY-NC)Iron Man and Batman are trademarks of Marvel and DC. This is an unofficial fan project, not affiliated with or endorsed by either.