Mark Ku's Blog

Problem

We plan to launch a new computer case with a 4K touch screen. We intended to showcase product features in 3D, but we tried a lot of instructional video texture tutorials and none of them worked properly in iOS 16. White PC case displaying Tetris game on its transparent side screen

iOS has many limit. I tried many times and sorted out the key points

  • Using native html video outside of Three.js canvus
  • Video must be mutte
  • Disable auto play
  • playsInline
  • crossOrigin="anonymous"
  • display none
  • Video url must have full domain name with https

Source Code

Using native html video outside of Three.js canvus

<Canvas>
...
</Canvas>
  <video
                        id="video"
                        playsInline
                        webkit-playsinline
                        muted
                        loop
                        style={{ display: 'none' }}
                        crossOrigin="anonymous"
                    >
                        <source src={videoUrl} type="video/mp4"></source>
                    </video>

Using Video Texture


import { SHOW_ROOM_3D_URL } from '@/const/const-3d';
import { CanvasContext } from '@/lib/context/3d-showroom/canvas-context';
import { useGLTF, useTexture } from '@react-three/drei';
import React, { useContext } from 'react';
import * as THREE from 'three';
import { GLTF } from 'three-stdlib';

type GLTFResult = GLTF & {
    nodes: {
        Cube: THREE.Mesh;
    };
    materials: {
        ['default']: THREE.MeshStandardMaterial;
    };
};

type ContextType = Record<string, React.ForwardRefExoticComponent<JSX.IntrinsicElements['mesh']>>;

export function VideoCanvas(props: JSX.IntrinsicElements['group']) {
    const { nodes, materials } = useGLTF(SHOW_ROOM_3D_URL + 'y70/video-canvas.glb') as GLTFResult;

    const {
        videoPlay: { isPlaying },
    } = useContext(CanvasContext);

    const touchScreenImgTexture = useTexture(SHOW_ROOM_3D_URL + 'y70/hyte-y70-case-touch-screen.png');
    const video = document.getElementById('video');

    const VideoMaterial = () => {
        if (video instanceof HTMLVideoElement) {
            const texture = new THREE.VideoTexture(video);

            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.repeat.x = -1; //  -1 為鏡像翻轉
            texture.flipY = true;

            texture.repeat.set(1, 1);

            return (
                <mesh
                    scale={[2.8, 2, 1]}
                    rotation={[0, -Math.PI / 4, 0]}
                    geometry={nodes.Cube.geometry}
                    material={materials.default}
                    castShadow
                >
                    <planeGeometry />
                    {isPlaying && <meshBasicMaterial side={THREE.FrontSide} map={texture} toneMapped={false} />}
                    {!isPlaying && (
                        <meshBasicMaterial side={THREE.FrontSide} map={touchScreenImgTexture} toneMapped={false} />
                    )}
                </mesh>
            );
        }
        return <></>;
    };

    return (
        <group {...props} dispose={null}>
            <mesh
                geometry={nodes.Cube.geometry}
                material={materials.default}
                position={[-0.114, 0.253, 0.1925]}
                rotation={[0, Math.PI / 4, 0]}
                scale={[0.0001, 0.175, 0.054]}
            >
                <VideoMaterial />
            </mesh>
        </group>
    );
}

useGLTF.preload(SHOW_ROOM_3D_URL + 'y70/video-canvas.glb');

Result

it's work for us. Hope it can help you too. Web browser displaying 3D white PC case with internal video screen

Author

Mark Ku

擁有 10+ 年經驗的資深軟體工程師,現為 AI 應用 Builder,專注於大型平台架構與簡化複雜系統設計,從電商系統到訂閱與收費平台,結合 AI Agent、AI 整合與自動化開發,打造高效率且可持續演進的產品技術基礎。Read More

Found this useful?

The author's free tools, daily podcasts and newsletter are all here.

Mark Ku · This article is licensed under CC BY 4.0. Credit the author and link back to the original when reusing it.

Comments

Subscribe to Newsletter

Subscribe to get new posts delivered instantly — never miss a tech share.

By submitting, you agree to receive emails. You can anytime.

Popular Posts

View all
Mark Ku
··602

Oracle Cloud Always Free Tier: Linux Host and Static IP for a $0 Cloud Solution

Oracle Cloud Always Free Tier: Linux Host and Static IP for a $0 Cloud Solution
Mark Ku
··490

Say Goodbye to Postman's Fee Trap! A Hands-on Guide to Bruno, the Open-Source Git-Native API Testing Powerhouse.

Say Goodbye to Postman's Fee Trap! A Hands-on Guide to Bruno, the Open-Source Git-Native API Testing Powerhouse.
Mark Ku
··333

A Free, Open-Source, Notion-like Knowledge Base — A Complete Guide to Deploying and Backing Up Outline Wiki

A Free, Open-Source, Notion-like Knowledge Base — A Complete Guide to Deploying and Backing Up Outline Wiki
Mark Ku
··264

Training Your Own AI Voice: Hardware Requirements, Open-Source Model Comparison, and LoRA Fine-Tuning

Training Your Own AI Voice: Hardware Requirements, Open-Source Model Comparison, and LoRA Fine-Tuning
Mark Ku
··221

Building an Efficient API Management Platform: Deploying Kong Gateway from Scratch - Part 1

Building an Efficient API Management Platform: Deploying Kong Gateway from Scratch - Part 1
Mark Ku
··215

Setting Up Samba on Ubuntu to Share Folders with Windows 11

Setting Up Samba on Ubuntu to Share Folders with Windows 11