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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@hashiprobr/expo-three-view

v1.0.19

Published

An Expo Component for Three.js visualization with auto-resizing and built-in orbit controls

Downloads

26

Readme

expo-three-view

An Expo Component for Three.js visualization with auto-resizing and built-in orbit controls

The ThreeView component simplifies the usage of Three.js for simple 3D visualization. It automatically adjusts the camera aspect and context dimensions on resize and offers orbit controls out of the box:

  • rotate: drag with one finger (Android or iOS) or mouse (web);

  • pan: drag with two fingers (Android or iOS) or shift+mouse (web);

  • zoom: pinch (Android or iOS) or mouse wheel (web).

The implementation was heavily inspired by Evan Bacon's expo-three-orbit-controls.

Peer dependencies

{
    "@hashiprobr/react-use-mount-and-update": "1.0.5",
    "@hashiprobr/react-use-refs": "1.0.12",
    "expo": "45.0.0",
    "expo-gl": "11.3.0",
    "expo-three": "6.1.0",
    "react": "17.0.2",
    "react-native": "0.68.2",
    "react-native-gesture-handler": "2.2.1",
    "react-native-reanimated": "2.8.0",
    "three": "0.142.0"
}

Install

With npm:

npm install @hashiprobr/expo-three-view

With yarn:

yarn add @hashiprobr/expo-three-view

With expo:

expo install @hashiprobr/expo-three-view

If using Expo, add the module to webpack.config.js:

const createExpoWebpackConfigAsync = require('@expo/webpack-config');

module.exports = async function (env, argv) {
    const config = await createExpoWebpackConfigAsync({
        ...env,
        babel: {
            dangerouslyAddModulePathsToTranspile: [
                '@hashiprobr/expo-three-view',
            ],
        },
    }, argv);
    return config;
};

If webpack.config.js does not exist, create it with:

expo customize:web

Props

| name | description | |-----------|------------------------------------------------------------------------------------------------------| | onCreate | a funcion called after the rendering context has been created or recreated (see below for arguments) | | onResize | a funcion called after the component is resized (no arguments) | | onDispose | a funcion called before the renderer is disposed (no arguments) |

...View props

onCreate

Receives an object with four properties:

  • renderer, a special expo-three renderer that uses a rendering context provided by an Expo GLView, and automatically updates its dimensions accordingly;

  • scene, an initially empty Three.js scene;

  • camera, a special Three.js perspective camera that sets the argument of lookAt as the orbit controls center, and automatically updates its aspect according to the rendering context size;

  • canvas, an object with three methods:

    • refresh, that executes a single render using the renderer, scene, and camera above;

    • play, that starts an animation based on a given function, using the renderer, scene, and camera above;

    • stop, that stops the animation.

This function is called the first time the context is created and whenever the context is recreated for whatever reason. Please note that, while the renderer is updated on each call, all other arguments remain the same. This means you don't need to rebuild the scene on each call.

onResize

This function is called whenever the component is resized. The most common usage is calling refresh, but note that this is not necessary when an animation is running.

onDispose

This function is called whenever the renderer is disposed. This happens either on unmount or when the context is recreated for whatever reason. The most common usage is executing clean up tasks.

Example

Simple example without animation:

import {
    AmbientLight,
    BoxBufferGeometry,
    Fog,
    GridHelper,
    Mesh,
    MeshStandardMaterial,
    PointLight,
    SpotLight,
} from 'three';

import React from 'react';

import ThreeView from '@hashiprobr/expo-three-view';

export default function MyComponent() {
    let refresh;

    function onCreate({ renderer, scene, camera, canvas }) {
        const sceneColor = 0x6ad6f0;
        renderer.setClearColor(sceneColor);

        scene.fog = new Fog(sceneColor, 1, 10000);
        scene.add(new GridHelper(10, 10));

        const ambientLight = new AmbientLight(0x101010);
        scene.add(ambientLight);

        const pointLight = new PointLight(0xffffff, 2, 1000, 1);
        pointLight.position.set(0, 200, 200);
        scene.add(pointLight);

        const spotLight = new SpotLight(0xffffff, 0.5);
        spotLight.position.set(0, 500, 100);
        spotLight.lookAt(scene.position);
        scene.add(spotLight);

        const geometry = new BoxBufferGeometry(1.0, 1.0, 1.0);
        const material = new MeshStandardMaterial({ color: 0xff0000 });
        const cube = new Mesh(geometry, material);
        scene.add(cube);

        camera.position.set(2, 5, 5);
        camera.lookAt(cube.position);

        refresh = canvas.refresh;
        refresh();
    }

    function onResize() {
        refresh();
    }

    return (
        <ThreeView
            style={{
                flexGrow: 1,
            }}
            onCreate={onCreate}
            onResize={onResize}
        />
    );
}

Simple example with animation:

import {
    AmbientLight,
    BoxBufferGeometry,
    Fog,
    GridHelper,
    Mesh,
    MeshStandardMaterial,
    PointLight,
    SpotLight,
} from 'three';

import React from 'react';

import ThreeView from '@hashiprobr/expo-three-view';

export default function MyComponent() {
    function onCreate({ renderer, scene, camera, canvas }) {
        const sceneColor = 0x6ad6f0;
        renderer.setClearColor(sceneColor);

        scene.fog = new Fog(sceneColor, 1, 10000);
        scene.add(new GridHelper(10, 10));

        const ambientLight = new AmbientLight(0x101010);
        scene.add(ambientLight);

        const pointLight = new PointLight(0xffffff, 2, 1000, 1);
        pointLight.position.set(0, 200, 200);
        scene.add(pointLight);

        const spotLight = new SpotLight(0xffffff, 0.5);
        spotLight.position.set(0, 500, 100);
        spotLight.lookAt(scene.position);
        scene.add(spotLight);

        const geometry = new BoxBufferGeometry(1.0, 1.0, 1.0);
        const material = new MeshStandardMaterial({ color: 0xff0000 });
        const cube = new Mesh(geometry, material);
        scene.add(cube);

        camera.position.set(2, 5, 5);
        camera.lookAt(cube.position);

        canvas.play(() => {
            cube.rotation.y += 0.05;
            cube.rotation.x += 0.025;
        });
    }

    return (
        <ThreeView
            style={{
                flexGrow: 1,
            }}
            onCreate={onCreate}
        />
    );
}

Slightly more complex example with animation, that considers the possibility of losing the context and cleans up on unmount:

import {
    AmbientLight,
    BoxBufferGeometry,
    Fog,
    GridHelper,
    Mesh,
    MeshStandardMaterial,
    PointLight,
    SpotLight,
} from 'three';

import React, { useRef, useEffect } from 'react';

import ThreeView from '@hashiprobr/expo-three-view';

export default function MyComponent() {
    const ref = useRef(null);

    function onCreate({ renderer, scene, camera, canvas }) {
        const sceneColor = 0x6ad6f0;
        renderer.setClearColor(sceneColor);

        let update;

        if (ref.current) {
            update = ref.current.update;
        } else {
            camera.position.set(2, 5, 5);

            scene.fog = new Fog(sceneColor, 1, 10000);
            scene.add(new GridHelper(10, 10));

            const ambientLight = new AmbientLight(0x101010);
            scene.add(ambientLight);

            const pointLight = new PointLight(0xffffff, 2, 1000, 1);
            pointLight.position.set(0, 200, 200);
            scene.add(pointLight);

            const spotLight = new SpotLight(0xffffff, 0.5);
            spotLight.position.set(0, 500, 100);
            spotLight.lookAt(scene.position);
            scene.add(spotLight);

            const geometry = new BoxBufferGeometry(1.0, 1.0, 1.0);
            const material = new MeshStandardMaterial({ color: 0xff0000 });
            const cube = new Mesh(geometry, material);
            scene.add(cube);

            camera.lookAt(cube.position);

            update = () => {
                cube.rotation.y += 0.05;
                cube.rotation.x += 0.025;
            }

            ref.current = { geometry, material, update };
        }

        canvas.play(update);
    }

    useEffect(() => {
        return () => {
            if (ref.current) {
                ref.material.dispose();
                ref.geometry.dispose();
                ref.current = null;
            }
        };
    });

    return (
        <ThreeView
            style={{
                flexGrow: 1,
            }}
            onCreate={onCreate}
        />
    );
}