How to use ExtrudeGeometry with functional components

Hello, I have been searching for an answer or at least some tutorial on how to use ExtrudeGeometry with FC, to no avail. My goal is to create a hollow box (with the floor, roof and two walls) which was successful without React/TS bindings.

App.tsx

<CameraControls>
  {cabinets?.map(({ height, width, depth, name }) => (
    <group key={name}>
      <Cabinet
        height={height}
        width={width}
        depth={depth}
      >
      </Cabinet>
    </group>
</CameraControls>

Cabinet.tsx

import React, { FC, MutableRefObject, useEffect, useRef, useState, useMemo } from 'react'
import { Box } from '@react-three/drei'
import { MeshProps } from '@react-three/fiber'
import {
  BufferGeometry,
  Material,
  Mesh,
  DoubleSide,
  Object3D,
  Vector3,
  Shape
} from 'three'

interface Props extends MeshProps {
  position: [number, number, number]
  width: number
  height: number
  depth: number
}

export type CabinetRef = MutableRefObject<
  Mesh<BufferGeometry, Material | Material[]>
>

export const Cabinet: FC<Props> = ({
  height,
  width,
  depth,
  ...props
}) => {
  const mesh = useRef<THREE.Mesh>(null!)
  const extrudeSettings = {
    amount: 12,
    bevelEnabled: true,
    bevelThickness: 0.0,
    bevelSize: 0.0,
    bevelSegments: 0,
    material: 0,
    extrudeMaterial: 1
  }
  const extrusion = new Path()
  extrusion.moveTo(-0.25, -0.25)
  extrusion.lineTo(-200, -0.25)
  extrusion.lineTo(-200, -200)
  extrusion.lineTo(-0.25, -200)
  extrusion.lineTo(-0.25, -0.25)

  return (
    <TransformControls show={active} position={position]>
      <Box
        {...props}
        ref={mesh}
        args={[width, height, depth]}
        castShadow
        receiveShadow
      >
        <meshStandardMaterial attach="material" color={color} />
      </Box>
    </TransformControls>
  )

The files of course have been pruned of irrelevant parts, but the main thing is that the current code produces boxes of right size and right position in the scene. However, for the love of my life I cannot find the correct way to make the boxes hollow; I tried to add extrudeGeometry with various values to Box, but no extrusions came visible although the code did build and run without errors. Can someone lend me a helping hand with this?

what is box? i don’t see any mention of ExtrudeGeometry in there. to form a component is quite simple, you just need to categorize props, state and effects, and then plot out the view.

Managing imperative code

Stick local dynamic state into useMemo, local static state into useState, then write out everything else declaratively. This is how you can quickly form reactive, re-usable components that can be bound to a store, graphql, etc.

function Extrusion({ start = [0, 0], paths, ...props }) {
  const shape = useMemo(() => {
    const shape = new THREE.Shape()
    shape.moveTo(...start)
    paths.forEach((path) => shape.bezierCurveTo(...path))
    return shape
  }, [start, paths])
  return (
    <mesh>
      <extrudeGeometry args={[shape, props]} />
      <meshPhongMaterial />
    </mesh>
  )
}

function Scene() {
  return (
    <Extrusion
      start={[25, 25]}
      paths={[
        [25, 25, 20, 0, 0, 0],
        [30, 0, 30, 35, 30, 35],
        [30, 55, 10, 77, 25, 95],
      ]}
      bevelEnabled
      amount={8} />

ps Basic demo (forked) - CodeSandbox (tried to make a bird but i suck at math)

if you already have the working code to build that cabinet you should be able to re-purpose the component.

Hi and thanks for the answer! The Box is imported from @react-three/drei. What I am aiming for are pictured here (sorry for the quality :joy:): https://imgur.com/a/C4FE8GY

I updated my original code to the original post to be bit more comprehensive. I tried defining Extrusion to Cabinet.tsx like this (with hardcoded paths to start):

function Extrusion({ start = [0, 0], paths, ...props }:{start:[number, number], paths:[number, number][], bevelEnabled:boolean, amount:number}) {
  const shape = useMemo(() => {
    const shape = new Shape()
    shape.moveTo(...start)
    paths = [[-100, 0], [-100, -300], [0, -300]]
    paths.forEach((path: [number, number]) => shape.lineTo(...path))
    shape.lineTo(0, 0)
    return shape
  }, [start, paths])
  return (
    <mesh>
      <extrudeGeometry args={[shape, props]} />
      <meshStandardMaterial color="red" />
    </mesh>
  )
}

and used it in the Cabinet’s return like this:

        <Extrusion 
          start={[0, 0]}
          paths={[[0, 0]]}
          bevelEnabled
          amount={8}
        />
        <meshStandardMaterial
          attach="material"
          color={color}
          side={DoubleSide}
        />

Nevertheless, the extrusions don’t appear in the Cabinets, they still are solid cabinets.