Skip to content

Instantly share code, notes, and snippets.

@Typiqally
Last active April 17, 2024 15:05
Show Gist options
  • Save Typiqally/d2acdab215a4c76902aabf90cdd162f0 to your computer and use it in GitHub Desktop.
Save Typiqally/d2acdab215a4c76902aabf90cdd162f0 to your computer and use it in GitHub Desktop.
OrientationCube for React and TailwindCSS, can be used with Three.js easily
/* Example usage
const [rotationMatrix, setRotationMatrix] = useState<number[]>(new Array(16).fill(0));
<OrientationCube
sizeInPixels={64}
rotationMatrix={rotationMatrix}
/>
setRotationMatrix(camera.matrixWorldInverse.clone().elements);
*/
import {CSSProperties} from 'react';
export enum Orientation {
Front = 'front',
Right = 'right',
Back = 'back',
Left = 'left',
Top = 'top',
Bottom = 'bottom',
}
interface Props {
sizeInPixels: number;
rotationMatrix: number[];
labels?: { [key in Orientation]: string }
className?: string;
onFaceClicked?: (orientation: Orientation) => void;
}
export function OrientationCube(props: Props) {
const sizeInPixelsHalved = props.sizeInPixels / 2;
const styles: { [key in Orientation]: CSSProperties } = {
front: {transform: `rotateY(0deg) translateZ(${sizeInPixelsHalved}px)`},
right: {transform: `rotateY(90deg) translateZ(${sizeInPixelsHalved}px)`},
back: {transform: `rotateY(180deg) translateZ(${sizeInPixelsHalved}px)`},
left: {transform: `rotateY(-90deg) translateZ(${sizeInPixelsHalved}px)`},
top: {transform: `rotateX(90deg) translateZ(${sizeInPixelsHalved}px)`},
bottom: {transform: `rotateX(-90deg) translateZ(${sizeInPixelsHalved}px)`},
};
const convertRotationMatrixToCss = (rotationMatrix: number[]): CSSProperties => {
return {
transform: `translateZ(-${sizeInPixelsHalved}px) matrix3d(
${rotationMatrix[0]}, ${-rotationMatrix[1]}, ${rotationMatrix[2]}, 0,
${-rotationMatrix[4]}, ${rotationMatrix[5]}, ${-rotationMatrix[6]}, 0,
${rotationMatrix[8]}, ${-rotationMatrix[9]}, ${rotationMatrix[10]}, 0,
0, 0, 0, 1)`
};
};
const handleFaceClicked = (orientation: Orientation) => {
if (props.onFaceClicked) {
props.onFaceClicked(orientation);
}
};
const getLabelForOrientation = (orientation: Orientation): string => {
return props.labels && orientation in props.labels
? props.labels[orientation]
: orientation.valueOf();
};
return <div
className="transform-style-3d relative " style={{
width: `${props.sizeInPixels}px`,
height: `${props.sizeInPixels}px`,
...convertRotationMatrixToCss(props.rotationMatrix)
}}>
{Object.values(Orientation).map((o, index) => (
<div
className={`absolute flex select-none items-center justify-center border-2 border-white ${props.className ?? ''}`}
key={index}
style={{
width: `${props.sizeInPixels}px`,
height: `${props.sizeInPixels}px`,
...styles[o],
}}
onClick={() => handleFaceClicked(o)}>
{getLabelForOrientation(o)}
</div>
))}
</div>;
}
export default OrientationCube;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment