7.1 Example codes (1~10)

Click the Open Sandbox button. Then, you can run all the examples on this page by changing the value of the variable example in App.jsx.

import React, { useEffect, useId, useRef } from "react";
import { useFrame, useKeyDown, useRefEffect } from "threefy";
import * as THREE from "three";

import crate_gif from "../public/images/crate.gif";

const DemoBox = () => {
  const example = 3;

  if (example === 1) {
    return (
      <box
        position={[0, 0, 0]}
        scale={[15, 6, 12]}
        type={"phong"}
        color={"skyblue"}
      />
    );
  }

  if (example === 2) {
    return (
      <mesh scale={8}>
        <boxGeometry />
        <meshStandardMaterial color={0xaa22ff} />
      </mesh>
    );
  }

  if (example === 3) {
    const ref = useRef(null);

    useFrame((t) => {
      if (ref.current) {
        const box = ref.current;
        box.rotation.x = t;
        box.rotation.y = t * 0.5;
        box.scale.setScalar(8 * (1.0 + 0.5 * Math.sin(t)));
      }
    });

    return <box ref={ref} scale={8} type={"standard"} color={0xaa22ff} />;
  }
};

const DemoCubes = () => {
  const example = 2;

  if (example === 1) {
    return (
      <>
        {Array(200)
          .fill()
          .map((v, i) => {
            const x = (Math.random() * 2 - 1) * 20; // -20 ~ 20
            const y = (Math.random() * 2 - 1) * 20;
            const z = (Math.random() * 2 - 1) * 20;
            const c = Math.random() * 0xffffff;
            return (
              <mesh key={i} position={[x, y, z]} scale={1.5}>
                <boxGeometry />
                <meshPhongMaterial color={c} />
              </mesh>
            );
          })}
      </>
    );
  }

  if (example === 2) {
    const id = useId();
    return (
      <group position={[0, 0, 0]}>
        {Array(200)
          .fill()
          .map((v, i) => {
            const x = (Math.random() * 2 - 1) * 20; // -20 ~ 20
            const y = (Math.random() * 2 - 1) * 20;
            const z = (Math.random() * 2 - 1) * 20;
            const c = Math.random() * 0xffffff;
            return (
              <box
                key={`${id}-${i}`}
                position={[x, y, z]}
                scale={1.5}
                type={"phong"}
                color={c}
              />
            );
          })}
      </group>
    );
  }
};

const DemoUseRef = (props) => {
  const ref = useRef(null);

  useEffect(() => {
    if (ref.current) {
      const mesh = ref.current;
      console.log("Mesh accessed by ref.current:", mesh);
      mesh.rotation.x = Math.PI / 6;
      mesh.rotation.y = Math.PI / 3;
    }
  }, []);

  const { size, color } = props;

  return (
    <mesh ref={ref} scale={10} {...props}>
      <boxGeometry args={size} />
      <meshStandardMaterial color={color} />
    </mesh>
  );
};

const DemoUseFrame = (props) => {
  const ref = useRef(null);

  useFrame((t) => {
    // (cf) threefy = { scene, camera, renderer }
    if (ref.current) {
      const mesh = ref.current;
      mesh.rotation.x = t * 1.5;
    }
  });

  const { size, color } = props;

  return (
    <mesh ref={ref} scale={10} {...props}>
      <boxGeometry args={size} />
      <meshStandardMaterial color={color} />
    </mesh>
  );
};

const DemoUseRefEffect = (props) => {
  const ref = useRefEffect((mesh) => {
    mesh.rotation.x += Math.PI / 4;
    mesh.rotation.y += Math.PI / 4;
  });

  const { size, color } = props;

  return (
    <mesh ref={ref} scale={10} {...props}>
      <boxGeometry args={size} />
      <meshStandardMaterial color={color} />
    </mesh>
  );
};

const DemoUseKeyDown = () => {
  const ref = useRefEffect((box) => {
    const color = box.material.color;

    useKeyDown((e) => {
      switch (e.key) {
        case "r":
          color.set("red");
          break;
        case "g":
          color.set("green");
          break;
        case "b":
          color.set("blue");
          break;
        default:
          color.set("skyblue");
          break;
      }
    });
  });

  return <box ref={ref} scale={10} type={"phong"} color={"skyblue"} />;
};

const DemoMesh = () => {
  const example = 2;

  if (example === 1) {
    return (
      <mesh
        visible={true}
        position={[0, 0, 0]}
        rotation={[Math.PI / 4, 0, 0, "XYZ"]}
        scale={[20, 10, 10]}
        userData={{ hello: "world" }}
        update={function (dt, ct) {
          this.rotation.x += Math.sin(dt) * 2.0;
        }}
      >
        <boxGeometry args={[1, 1, 1]} />
        <meshStandardMaterial color="white" map="images/crate.gif" />
      </mesh>
    );
  }

  if (example === 2) {
    const geometry = new THREE.BoxGeometry();
    const material = new THREE.MeshStandardMaterial({ color: "blue" });
    const changeMaterial = (material, color = "white") => {
      material = material.clone();
      material.color.set(color);
      return material;
    };

    return (
      <object3D scale={10}>
        <mesh position={[-1, -1, 0]}>
          <boxGeometry />
          <meshStandardMaterial color={"red"} />
        </mesh>
        <mesh position={[1, -1, 0]} geometry={geometry}>
          <meshStandardMaterial color={"green"} />
        </mesh>
        <mesh position={[-1, 1, 0]} material={material}>
          <boxGeometry />
        </mesh>
        <mesh
          position={[1, 1, 0]}
          rotation={[Math.PI / 3, Math.PI / 6, 0]}
          geometry={geometry}
          material={changeMaterial(material, "yellow")}
        />
      </object3D>
    );
  }
};

const DemoGroup = () => {
  return (
    <group
      update={function (dt, ct) {
        this.rotation.z += 0.4 * dt;
      }}
    >
      <box
        update={function (dt, ct) {
          this.rotation.x += dt;
        }}
        position={[-8, -8, 0]}
        scale={[10, 10, 10]}
        type={"lambert"}
        color={"red"}
      />
      <box
        update={function (dt, ct) {
          this.rotation.y += dt;
        }}
        position={[8, -8, 0]}
        scale={[10, 10, 10]}
        type={"lambert"}
        color={"green"}
      />
      <box
        update={function (dt, ct) {
          this.rotation.z += dt;
        }}
        position={[-8, 8, 0]}
        scale={[10, 10, 10]}
        type={"lambert"}
        color={"blue"}
      />
      <box
        update={function (dt, ct) {
          this.scale.setScalar(10 + 3 * Math.sin(ct));
        }}
        position={[8, 8, 0]}
        scale={[10, 10, 10]}
        type={"lambert"}
        color={0xffffaa}
        map={crate_gif}
      />
    </group>
  );
};

const DemoBoxOrbit = () => {
  const example = 2; // two examples produce the same result

  function rotate(dt, ct) {
    this.rotation.z += dt;
  }

  if (example === 1) {
    return (
      <mesh update={rotate} position={[0, 0, 0]}>
        <boxGeometry />
        <meshStandardMaterial color={"red"} />
        <mesh update={rotate} position={[10, 0, 0]}>
          <boxGeometry />
          <meshStandardMaterial color={"green"} />
          <mesh position={[3, 0, 0]}>
            <boxGeometry />
            <meshStandardMaterial color={"yellow"} />
          </mesh>
        </mesh>
      </mesh>
    );
  }

  if (example === 2) {
    return (
      <box update={rotate} position={[0, 0, 0]} type={"standard"} color={"red"}>
        <box
          update={rotate}
          position={[10, 0, 0]}
          type={"standard"}
          color={"green"}
        >
          <box position={[3, 0, 0]} type={"standard"} color={"yellow"} />
        </box>
      </box>
    );
  }
};

const DemoVortex = () => {
  const example = 2;

  if (example === 1) {
    function rotate(dt, ct) {
      this.rotation.z += dt;
    }
    return (
      <group>
        <box position={[0, 0, 0]} type={"lambert"} color={"red"} />
        <group update={rotate}>
          <box
            update={rotate}
            position={[12, 0, 0]}
            type={"lambert"}
            color={"blue"}
          />
          <group update={rotate}>
            <box
              update={rotate}
              position={[8, 0, 0]}
              type={"lambert"}
              color={"green"}
            />
            <group update={rotate}>
              <box
                update={rotate}
                position={[4, 0, 0]}
                type={"lambert"}
                color={"yellow"}
              />
            </group>
          </group>
        </group>
      </group>
    );
  }

  if (example === 2) {
    function rotate(dt, ct) {
      this.rotation.z += dt;
    }

    const numBox = 20;

    let h,
      s = 1,
      l = 0.5;
    const colors = [];
    const col = new THREE.Color();
    for (let i = 0; i < numBox; i++) {
      h = i / numBox;
      colors.push(col.setHSL(h, s, l).getHex());
    }

    const dr = 2;
    let r = 0;
    let box = (
      <box
        update={rotate}
        position={[r, 0, 0]}
        type={"lambert"}
        color={"red"}
      />
    );
    let group = <group update={rotate}>{box}</group>;

    for (let i = 0; i < numBox; i++) {
      r += dr;
      box = (
        <box
          update={rotate}
          position={[r, 0, 0]}
          type={"lambert"}
          color={colors[i]}
        />
      );
      if (i === numBox - 1) {
        // group = <group>{box}{group}</group>;
        <group>
          {box}
          {group}
        </group>;
      } else {
        group = (
          <group update={rotate}>
            {box}
            {group}
          </group>
        );
      }
    }
    return group;
  }
};

const DemoExamples = ({ example }) => {
  switch (example) {
    case 1:
      return <DemoBox />;
    case 2:
      return <DemoCubes />;
    case 3:
      return <DemoUseRef />;
    case 4:
      return <DemoUseFrame />;
    case 5:
      return <DemoUseRefEffect />;
    case 6:
      return <DemoUseKeyDown />;
    case 7:
      return <DemoMesh />;
    case 8:
      return <DemoGroup />;
    case 9:
      return <DemoBoxOrbit />;
    case 10:
      return <DemoVortex />;
  }
};

export { DemoExamples };

Last updated