Skip to content
Back to skills

Html To 3d Texture

ASecurity

Capture HTML/React components as PNG or canvas textures for 3D model screens — Playwright, html2canvas, live CanvasTexture, resolution guide, rounded-corner masking.

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 16, 2026
ai-agentsjavascriptgojavareactnode

Works with

  • cli

Security analysis

A100/100

Scanned October 16, 2026

npx -y skills add RaNDoM6913/claude-code-superkit --skill html-to-3d-texture --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Html To 3d Texture?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Html To 3d Texture
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/random6913-html-to-3d-texture-claude-code-superkit/badge)](https://www.skillsdirectory.com/skills/random6913-html-to-3d-texture-claude-code-superkit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: html-to-3d-texture
description: Capture HTML/React components as PNG or canvas textures for 3D model screens — Playwright, html2canvas, live CanvasTexture, resolution guide, rounded-corner masking.
tokens: 1514
---

# HTML to 3D Texture Pipeline

## Purpose

Display web UI on a 3D surface: render a React component, capture it as a PNG or canvas, apply it as a Three.js texture on the model's screen mesh.

```
React Component → Capture (Playwright/html2canvas) → PNG/Canvas → Three.js Texture → 3D Mesh
```

## Use when / Do not use

- **Use when**: a 3D model (phone, laptop, tablet) must show real web UI on its screen.
- **Do not use when**: the UI must stay clickable/scrollable on the 3D surface — a texture is a flat image. Use `@react-three/drei` `<Html>` instead.

## Hard Rules

- Set `texture.colorSpace = THREE.SRGBColorSpace` on every texture built from a capture — otherwise colors wash out.
- Capture at 2x (`deviceScaleFactor: 2` / `scale: 2`) — 1x textures look blurry on retina screens.
- html2canvas re-parses the entire DOM subtree on every call — this cost applies to Method 2 AND Method 3. In any repeated-capture loop, cap refresh at 1–2 fps for production; higher rates (e.g. 10 fps) are local-dev demos only.

## Workflow

1. Pick the capture method from the decision table below.
2. Capture at 2x using that method's code.
3. Post-process if the screen needs rounded corners (sharp recipe below).
4. Apply as texture with `SRGBColorSpace` set (PNG → `THREE.TextureLoader`; canvas → `THREE.CanvasTexture`).

## Decision table — which method

| Content on the 3D screen | Method |
|--------------------------|--------|
| Static — never changes at runtime | **Method 1** — Playwright PNG (build-time) |
| Changes on discrete events (user action, data loaded) | **Method 2** — one-shot html2canvas per event |
| Changes continuously (timers, animations, live data) | **Method 3** — throttled html2canvas loop |
| Must remain interactive (clicks, scroll, inputs) | Not a texture — drei `<Html>` |

Default when unsure: **Method 1** — best quality, zero runtime cost.

## Method 1: Playwright Capture (build-time, best quality)

Best for: production screenshots, pixel-perfect captures.

```javascript
// scripts/capture-screen.mjs
import { chromium } from 'playwright';

const PORT = process.argv[2] || 3000;
const WIDTH = 440;   // Native screen width
const HEIGHT = 956;  // Native screen height
const SCALE = 2;     // Retina (output: 880x1912)

async function capture() {
  const browser = await chromium.launch();
  const page = await browser.newPage({
    viewport: { width: WIDTH, height: HEIGHT },
    deviceScaleFactor: SCALE,
  });

  await page.goto(`http://localhost:${PORT}/capture`);
  await page.waitForLoadState('networkidle');

  // Find target element
  const el = await page.locator('[data-screen-id="main"]');
  await el.screenshot({
    path: 'public/textures/screen.png',
    type: 'png',
  });

  await browser.close();
  console.log(`Captured: ${WIDTH * SCALE}x${HEIGHT * SCALE}px`);
}

capture();
```

## Method 2: One-shot html2canvas (event-driven runtime capture)

Best for: content that changes on discrete events. Call once per change event (button click, data arrival) — do NOT wrap this in an interval; that is Method 3.

```tsx
import html2canvas from 'html2canvas';
import * as THREE from 'three';

async function captureToTexture(element: HTMLElement): Promise<THREE.CanvasTexture> {
  const canvas = await html2canvas(element, {
    scale: 2,
    useCORS: true,
    backgroundColor: null, // transparent
  });

  const texture = new THREE.CanvasTexture(canvas);
  texture.colorSpace = THREE.SRGBColorSpace;
  texture.needsUpdate = true;

  return texture;
}
```

## Method 3: Throttled html2canvas loop (continuous updates)

Best for: UI that changes continuously while displayed on the 3D surface. Same capture as Method 2, driven by a timer — so the html2canvas cost from Hard Rules repeats every tick. Keep `FPS` at 1–2 in production.

```tsx
const FPS = 2; // production-safe (1-2 fps). 10 fps = local-dev demo only — CPU-heavy.

function useHTMLTexture(ref: React.RefObject<HTMLDivElement>) {
  const textureRef = useRef<THREE.CanvasTexture | null>(null);

  useEffect(() => {
    const interval = setInterval(async () => {
      if (!ref.current) return;
      const canvas = await html2canvas(ref.current, { scale: 2 });
      if (textureRef.current) {
        textureRef.current.image = canvas;
        textureRef.current.needsUpdate = true;
      } else {
        textureRef.current = new THREE.CanvasTexture(canvas);
        textureRef.current.colorSpace = THREE.SRGBColorSpace;
      }
    }, 1000 / FPS);

    return () => clearInterval(interval);
  }, [ref]);

  return textureRef;
}
```

## Resolution Guide

| Device | Native (pts) | @2x (px) | Use for |
|--------|-------------|----------|---------|
| iPhone 15 Pro | 393x852 | 786x1704 | Phone model screen |
| iPhone 16 Pro Max | 440x956 | 880x1912 | Large phone model |
| iPad Pro 11" | 834x1194 | 1668x2388 | Tablet model |
| MacBook Pro 14" | 1512x982 | 3024x1964 | Laptop model |

## Applying Rounded Corners

PNG with transparent rounded corners for phone screens:

```javascript
// Using sharp (Node.js)
import sharp from 'sharp';

const RADIUS = 124; // 62pt * 2x scale
const { width, height } = await sharp('screen.png').metadata();

const mask = Buffer.from(
  `<svg width="${width}" height="${height}">
    <rect x="0" y="0" width="${width}" height="${height}" 
          rx="${RADIUS}" ry="${RADIUS}" fill="white"/>
  </svg>`
);

await sharp('screen.png')
  .ensureAlpha()
  .composite([{ input: mask, blend: 'dest-in' }])
  .png()
  .toFile('screen-rounded.png');
```

## Tips

- Always capture at 2x for retina quality
- Use `data-screen-id` attribute to find elements reliably
- Remove debug borders/outlines before capture
- Test with `sips -g pixelWidth -g pixelHeight` (macOS) to verify dimensions
- Set `backgroundColor: null` for transparent backgrounds when needed

## Recap — non-negotiables

- `SRGBColorSpace` on every capture-derived texture.
- Capture at 2x, always.
- Repeated html2canvas capture: 1–2 fps in production; 10 fps only as a labeled local-dev demo value.
- Unsure which method: Method 1 (Playwright PNG).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.