{"id":21410578,"url":"https://github.com/isoteriksoftware/react-gallery-3d","last_synced_at":"2025-07-14T02:31:04.205Z","repository":{"id":206457285,"uuid":"716575572","full_name":"isoteriksoftware/react-gallery-3d","owner":"isoteriksoftware","description":"A library for creating 3D galleries in React applications.","archived":false,"fork":false,"pushed_at":"2023-11-15T12:31:46.000Z","size":228,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-03-14T21:24:14.832Z","etag":null,"topics":["3d-gallery","gallery","react","react-gallery"],"latest_commit_sha":null,"homepage":"https://react-gallery-3d-demo.vercel.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/isoteriksoftware.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-09T12:30:13.000Z","updated_at":"2024-05-30T09:33:18.642Z","dependencies_parsed_at":"2023-11-09T19:10:42.099Z","dependency_job_id":"583a4cdf-fc6c-457a-9591-dee808f66b4f","html_url":"https://github.com/isoteriksoftware/react-gallery-3d","commit_stats":null,"previous_names":["isoteriksoftware/react-gallery-3d"],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isoteriksoftware%2Freact-gallery-3d","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isoteriksoftware%2Freact-gallery-3d/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isoteriksoftware%2Freact-gallery-3d/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isoteriksoftware%2Freact-gallery-3d/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/isoteriksoftware","download_url":"https://codeload.github.com/isoteriksoftware/react-gallery-3d/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225269281,"owners_count":17447504,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d-gallery","gallery","react","react-gallery"],"created_at":"2024-11-22T17:40:41.311Z","updated_at":"2024-11-22T17:40:42.062Z","avatar_url":"https://github.com/isoteriksoftware.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Preview](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/109d9120-07f0-46fd-b43e-21a127979e25)\n\n[![Version](https://img.shields.io/npm/v/react-gallery-3d)](https://www.npmjs.com/package/react-gallery-3d)\n[![Downloads](https://img.shields.io/npm/dt/react-gallery-3d.svg)](https://www.npmjs.com/package/react-gallery-3d)\n\n`react-gallery-3d` provides React components to create awesome 3D galleries. \nIt supports rendering with solid colors, images, videos, etc., offering a wide range of possibilities for showcasing media in a 3D environment.\nVersion 2 introduces exciting new features and optimizations to enhance your gallery-building experience.\n\n## New Features\n- **Transparent Items**: Gallery items can now be transparent, allowing you to create more complex and visually appealing galleries.\n- **Object Items**: You can now use custom three.js objects as gallery items, giving you more control over the appearance and behavior of your gallery.\n- **New Item Material API**: The item material API has been redesigned to make it easier to create and reuse custom materials for gallery items. Full control over the material properties is now possible.\n- **Support for Deeply Nested Gallery Items**: With v2.2.x, Gallery Items can now be rendered deep within the component tree, allowing for more complex and dynamic galleries.\n- **Support for Gallery with less than 3 items**: You can now render galleries with less than three items. This allows you to create galleries with one or two items.\n- **Support for Gallery Item Props Overrides**: You can now override the gallery item properties for individual items, allowing you to create galleries with items of different sizes and configuration.\n- **Improved Performance**: The library has been optimized to improve performance and reduce memory usage, making it faster and more efficient.\n\n## Demo\nCheck out the [live demo (playground)](https://react-gallery-3d-demo.vercel.app/) to see `react-gallery-3d` in action and explore its capabilities.\n\n## Table of Contents\n\u003c!-- TOC --\u003e\n  * [New Features](#new-features)\n  * [Demo](#demo)\n  * [Table of Contents](#table-of-contents)\n  * [Installation](#installation)\n  * [Peer Dependencies](#peer-dependencies)\n  * [Basic Usage](#basic-usage)\n  * [Advanced Usage](#advanced-usage)\n  * [Components](#components)\n    * [`\u003cGalleryScene/\u003e`](#galleryscene)\n      * [Props](#props)\n      * [Example Usage](#example-usage)\n    * [`\u003cGallery/\u003e`](#gallery)\n      * [Props](#props-1)\n      * [Example Usage](#example-usage-1)\n    * [`\u003cGalleryItem/\u003e`](#galleryitem)\n      * [Props](#props-2)\n      * [Example Usage](#example-usage-2)\n    * [`\u003cSolidColorItem/\u003e`](#solidcoloritem)\n      * [Props](#props-3)\n      * [Example Usage](#example-usage-3)\n    * [`\u003cImageItem/\u003e`](#imageitem)\n      * [Props](#props-4)\n      * [Example Usage](#example-usage-4)\n    * [`\u003cVideoItem/\u003e`](#videoitem)\n      * [Props](#props-5)\n      * [Example Usage](#example-usage-5)\n    * [`\u003cTransparentItem/\u003e`](#transparentitem)\n      * [Props](#props-6)\n      * [Example Usage](#example-usage-6)\n    * [`\u003cObjectItem/\u003e`](#objectitem)\n      * [Props](#props-7)\n      * [Example Usage](#example-usage-7)\n  * [Hooks](#hooks)\n    * [`useGalleryItem()`](#usegalleryitem)\n      * [Example Usage](#example-usage-8)\n    * [`usePlacementOnGalleryItem()`](#useplacementongalleryitem)\n    * [`useImageMaterial()`](#useimagematerial)\n      * [Example Usage](#example-usage-9)\n    * [`useVideoMaterial()`](#usevideomaterial)\n      * [Example Usage](#example-usage-10)\n  * [Breaking Changes](#breaking-changes)\n  * [Migration Guide](#migration-guide)\n    * [GalleryItem Material API](#galleryitem-material-api)\n      * [Before](#before)\n      * [Now](#now)\n    * [GalleryItemMaterial Implementations](#galleryitemmaterial-implementations)\n      * [Before](#before-1)\n      * [Now](#now-1)\n    * [Gallery Ground API](#gallery-ground-api)\n      * [Before](#before-2)\n      * [Now](#now-2)\n    * [Gallery Children](#gallery-children)\n      * [Before](#before-3)\n      * [Now](#now-3)\n    * [GalleryItem Properties](#galleryitem-properties)\n      * [Before](#before-4)\n      * [Now](#now-4)\n  * [Contributing](#contributing)\n\u003c!-- TOC --\u003e\n\n## Installation\n```bash\nnpm install react-gallery-3d three @react-three/fiber @react-three/drei\n```\nor\n```bash\nyarn add react-gallery-3d three @react-three/fiber @react-three/drei\n```\n\n## Peer Dependencies\nThis library is designed to work alongside `@react-three/drei`, `@react-three/fiber`, and `three.js`. These are listed as peer dependencies, meaning that it expects these packages to be present in your project:\n\n- `three.js`: A JavaScript 3D library that creates and displays animated 3D computer graphics in a web browser.\n- `@react-three/fiber`: A React renderer for three.js that brings declarative, reactive, and component-based patterns to 3D rendering.\n- `@react-three/drei`: A useful collection of helpers and abstractions for react-three-fiber.\n\nAs peer dependencies, they are not automatically installed when you install this library. You need to manually install them in your project, if not already present. This approach helps to avoid version conflicts and reduce bundle size.\n\n## Basic Usage\n```tsx\nimport { Gallery, GalleryScene, ImageItem, SolidColorItem, VideoItem } from \"react-gallery-3d\";\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cImageItem src=\"https://picsum.photos/1280/720\" /\u003e\n          \u003cSolidColorItem color=\"teal\" /\u003e\n          \u003cVideoItem\n            src=\"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\"\n            crossOrigin=\"anonymous\"\n          /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n\nThis renders a gallery with three items: a solid color, an image, and a video. The gallery is rendered in a canvas element using `react-three-fiber`.\n\n![Basic Gallery](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/62ce17c0-e097-45ba-bf65-08d8697752ba)\n\n\u003e **Note** \u003cbr/\u003e\n\u003e You may see a different image when you run the code because the image is fetched from an external source (picsum). The image may change each time you reload the page.\n\n## Advanced Usage\nYou can create more complex galleries by customizing the gallery items and their materials. \nThe following example demonstrates how to create a gallery with transparent items, custom materials, and models:\n\n```tsx\nimport {\n  Gallery,\n  GalleryScene,\n  ImageItem,\n  VideoItem,\n  TransparentItem,\n  ObjectItem,\n} from \"react-gallery-3d\";\nimport { useState } from \"react\";\nimport { Mesh } from \"three\";\nimport { useGLTF } from \"@react-three/drei\";\n\nfunction App() {\n  const [box, setBox] = useState\u003cMesh | null\u003e(null);\n  const { scene: model } = useGLTF(\"/models/low_poly_character_swordsman.glb\");\n  const [itemHeight] = useState(60);\n\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\n        orbitControls={{\n          autoRotate: true,\n          rotateSpeed: -1,\n          enableZoom: false,\n        }}\n        environment={{\n          preset: \"city\",\n        }}\n        camera={{\n          position: [0, 60, 150],\n          fov: 45,\n        }}\n        fog={{\n          color: \"black\",\n          near: 10,\n          far: 520,\n        }}\n        ground={{\n          position: [0, -itemHeight / 2, 0],\n          reflectorMaterial: {\n            mirror: 0.95,\n            resolution: 2048,\n            roughness: 1,\n            metalness: 0.7,\n          },\n        }}\n      \u003e\n        \u003cGallery\n          item={{\n            width: 150,\n            height: itemHeight,\n            radialSegments: 50,\n            innerRadiusPercent: 0.01,\n          }}\n        \u003e\n          \u003cTransparentItem /\u003e\n          \u003cVideoItem src=\"/videos/vid6.mp4\" /\u003e\n          \u003cImageItem src=\"/images/img1.jpg\" /\u003e\n          \u003cVideoItem src=\"/videos/vid4.mp4\" /\u003e\n          \u003cImageItem src=\"/images/img2.jpg\" /\u003e\n          \u003cObjectItem object={box} objectOffset={0} disableObjectRender\u003e\n            \u003cmesh ref={(boxObj) =\u003e setBox(boxObj)}\u003e\n              \u003cboxGeometry args={[10, 10, 10]} /\u003e\n              \u003cmeshStandardMaterial color=\"white\" /\u003e\n            \u003c/mesh\u003e\n          \u003c/ObjectItem\u003e\n          \u003cObjectItem\n            object={model}\n            objectProps={{\n              scale: [20, 20, 20],\n            }}\n            onObjectAlignmentChange={(object) =\u003e {\n              object.position.y = -itemHeight / 2;\n              object.rotateY(Math.PI);\n            }}\n          /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n\n![Advanced Gallery](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/41dbae3b-cba5-42c2-9b20-778ab9c76115)\n\n\u003e **Note** \u003cbr/\u003e\n\u003e The example uses a 3D model from the [low-poly-character-swordsman](https://sketchfab.com/3d-models/low-poly-character-swordsman-24aae01ca3a64a8c9dfc232840c2542b) collection on Sketchfab. \n\u003e The model, images, and videos are included in the `public` folder of the project.\n\n## Components\n\n### `\u003cGalleryScene/\u003e`\nThe `GalleryScene` is a wrapper around the `Canvas` component from `@react-three/fiber`. \nIt sets up the 3D environment, camera, lighting, fog, and controls for galleries. \nIt also provides a ground plane with a reflector material for realistic reflections.\n\nThis component can render galleries and other 3D objects.\nYou can customize the scene by passing props to the `GalleryScene` component.\n\n#### Props\n```tsx\ntype GallerySceneProps = Omit\u003cCanvasProps, \"children\"\u003e \u0026 {\n  /**\n   * The children to render.\n   *\n   * @default undefined\n   */\n  children?: ReactNode;\n\n  /**\n   * The background color of the scene.\n   *\n   * @default #000000\n   */\n  backgroundColor?: ColorRepresentation;\n\n  /**\n   * The Fog properties\n   *\n   * @default {\n   *   color: \"#000000\",\n   *   near: 10,\n   *   far: 400\n   * }\n   */\n  fog?: FogProps;\n\n  /**\n   * The OrbitControls properties.\n   *\n   * @default {\n   *   enableDamping: true,\n   *   enableZoom: true,\n   *   dampingFactor: 0.01,\n   *   autoRotate: true,\n   *   autoRotateSpeed: -1\n   * }\n   */\n  orbitControls?: OrbitControlsProps;\n\n  /**\n   * Whether to disable the controls.\n   *\n   * @default false\n   */\n  disableControls?: boolean;\n\n  /**\n   * Whether to disable the fog.\n   *\n   * @default false\n   */\n  disableFog?: boolean;\n\n  /**\n   * Whether to disable the environment.\n   *\n   * @default false\n   */\n  disableEnvironment?: boolean;\n\n  /**\n   * The Environment properties.\n   *\n   * @default {\n   *   preset: \"sunset\"\n   * }\n   */\n  environment?: EnvironmentProps;\n\n  /**\n   * The Ground properties.\n   *\n   * @default {\n   *   position: [0, -25, 0]\n   * }\n   */\n  ground?: GroundProps;\n\n  /**\n   * Whether to disable the ground.\n   *\n   * @default false\n   */\n  disableGround?: boolean;\n\n  /**\n   * The fallback to render while loading the scene.\n   */\n  suspenseFallback?: ReactNode;\n};\n```\n\n#### Example Usage\n```tsx\n\u003cGalleryScene\n  backgroundColor=\"#000000\"\n  fog={{\n    color: \"#000000\",\n    near: 10,\n    far: 400,\n  }}\n  orbitControls={{\n    enableDamping: true,\n    enableZoom: true,\n    dampingFactor: 0.01,\n    autoRotate: true,\n    autoRotateSpeed: -1,\n  }}\n  disableControls={false}\n  disableFog={false}\n  disableEnvironment={false}\n  environment={{\n    preset: \"sunset\",\n  }}\n  ground={{\n    position: [0, -25, 0],\n  }}\n  disableGround={false}\n\u003e\n  \u003cGallery\u003e\n    {/* Gallery items */}\n  \u003c/Gallery\u003e\n\n  \u003cGallery position-x={160}\u003e\n    {/* Gallery items */}\n  \u003c/Gallery\u003e\n\n  {/* Other 3D objects */}\n\u003c/GalleryScene\u003e\n```\n\n\u003cbr/\u003e\n\n### `\u003cGallery/\u003e`\nThe `Gallery` component is a container for gallery items. It arranges the items in a cylindrical layout around the center of the scene.\nIt requires at least three items to render.\n\nAll children of the `Gallery` are rendered. Once a `GalleryItem` is rendered, it is automatically placed on the gallery.\n`GalleryItem` components can be anywhere in the component tree (as a child of `Gallery`), and they will be correctly placed on the gallery.\n\nThe `Gallery` component automatically calculates the position and rotation of the items based on the number of items in the gallery.\nYou can modify the layout of gallery items by passing props to the `GalleryItem` component or its wrappers.\n\nIt accepts global props to customize the appearance and layout of the gallery items. Any of the props can be overridden for individual items.\nCheck the [GalleryItem component](#galleryitem) for the properties that can be overridden.\n\n#### Props\n```tsx\ntype GalleryProps = Omit\u003cGroupProps, \"children\" | \"ref\"\u003e \u0026 {\n  /**\n   * The children of the gallery.\n   */\n  children: GalleryChildren;\n\n  /**\n   * The global properties for all the items in the gallery.\n   *\n   * These properties are used when the gallery item properties are not provided.\n   */\n  item?: {\n    /**\n     * The width of the gallery item.\n     *\n     * @default 120\n     */\n    width?: number;\n\n    /**\n     * The height of the gallery item.\n     *\n     * @default 50\n     */\n    height?: number;\n\n    /**\n     * The number of radial segments.\n     *\n     * @default 50\n     */\n    radialSegments?: number;\n\n    /**\n     * The number of height segments.\n     *\n     * @default 1\n     */\n    heightSegments?: number;\n\n    /**\n     * The percentage of the outer radius to use as the inner radius.\n     *\n     * @default 0.01\n     */\n    innerRadiusPercent?: number;\n\n    /**\n     * The section angle of the gallery item.\n     *\n     * This property is calculated using the total number of items in the gallery when not provided.\n     */\n    sectionAngle?: number;\n  };\n};\n```\n\n#### Example Usage\n```tsx\n\u003cGallery\n  item={{\n    width: 120,\n    height: 50,\n    radialSegments: 50,\n    heightSegments: 1,\n    innerRadiusPercent: 0.01,\n  }}\n\u003e\n  {/* Gallery items */}\n\u003c/Gallery\u003e\n```\n\n\u003cbr/\u003e\n\n### `\u003cGalleryItem/\u003e`\nThe `GalleryItem` component is the base component for gallery items. It provides a common interface for all gallery items.\nThis can be used to create custom gallery items.\n\nAny 3D object can be a child of the `GalleryItem` component. \nChildren objects can be positioned and aligned correctly using `ObjectItem` or using the `usePlacementOnGalleryItem` hook\nfor more control over the placement of the object.\n\nThe component has a `material` prop that accepts a material or an array of materials to apply to the gallery item.\nThis allows you to customize the appearance of the gallery item.\n\nBy default, the `material` is automatically disposed when the component is unmounted.\nYou can disable this behavior by setting the `disableAutoDispose` prop to `true`.\n\n**Be careful when sharing materials between gallery items.\nIf you want to reuse a material, consider setting the `disableAutoDispose` prop to `true` to prevent the material from being disposed when one of the items is unmounted.**\n\n#### Props\n```tsx\ntype GalleryItemProps = MeshProps \u0026 {\n  /**\n   * The material to apply to the gallery item.\n   */\n  material: Material | Material[];\n\n  /**\n   * Disables the auto-disposal of the material.\n   *\n   * When set to true, the material will not be disposed of when the component is unmounted.\n   */\n  disableAutoDispose?: boolean;\n\n  /**\n   * The width of the gallery item.\n   *\n   * When not provided, the value is taken from the Gallery item properties.\n   */\n  width?: number;\n\n  /**\n   * The height of the gallery item.\n   *\n   * When not provided, the value is taken from the Gallery item properties.\n   */\n  height?: number;\n\n  /**\n   * The number of radial segments.\n   *\n   * When not provided, the value is taken from the Gallery item properties.\n   */\n  radialSegments?: number;\n\n  /**\n   * The number of height segments.\n   *\n   * When not provided, the value is taken from the Gallery item properties.\n   */\n  heightSegments?: number;\n\n  /**\n   * The percentage of the outer radius to use as the inner radius.\n   *\n   * When not provided, the value is taken from the Gallery item properties.\n   */\n  innerRadiusPercent?: number;\n\n  /**\n   * The section angle of the gallery item.\n   *\n   * When not provided, the value is taken from the Gallery item properties.\n   */\n  sectionAngle?: number;\n};\n```\n\n#### Example Usage\n```tsx\nimport { Gallery, GalleryItem, GalleryScene } from \"react-gallery-3d\";\nimport { useMemo, useState } from \"react\";\nimport { MathUtils, MeshStandardMaterial } from \"three\";\n\nfunction App() {\n  const [rotation] = useState(MathUtils.degToRad(10));\n\n  const greenMaterial = useMemo(\n    () =\u003e\n      new MeshStandardMaterial({\n        color: \"green\",\n        emissive: \"red\",\n        roughness: 0.5,\n        metalness: 1,\n      }),\n    [],\n  );\n\n  const redMaterial = useMemo(\n    () =\u003e\n      new MeshStandardMaterial({\n        color: \"red\",\n        emissive: \"blue\",\n        roughness: 0.5,\n        metalness: 1,\n      }),\n    [],\n  );\n\n  const blueMaterial = useMemo(\n    () =\u003e\n      new MeshStandardMaterial({\n        color: \"blue\",\n        emissive: \"green\",\n        roughness: 0.5,\n        metalness: 1,\n      }),\n    [],\n  );\n\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\n        ground={{\n          reflectorMaterial: {\n            metalness: 1,\n            roughness: 1,\n            mirror: 1,\n            resolution: 2048,\n          },\n        }}\n      \u003e\n        \u003cGallery\u003e\n          \u003cGalleryItem\n            material={greenMaterial}\n            sectionAngle={Math.PI / 4}\n            position-z={10}\n            rotation-z={rotation}\n          /\u003e\n          \u003cGalleryItem\n            material={greenMaterial}\n            sectionAngle={Math.PI / 2}\n            position-z={10}\n          /\u003e\n          \u003cGalleryItem\n            material={redMaterial}\n            rotation-z={rotation}\n            onPointerOver={() =\u003e console.log(\"Item Hovered!\")}\n          /\u003e\n          \u003cGalleryItem\n            material={blueMaterial}\n            rotation-z={rotation}\n            onClick={() =\u003e console.log(\"Item Clicked!\")}\n          /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n![Example Output](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/715871eb-1bb8-4d81-992a-32947448370b)\n \n\u003cbr/\u003e\n\n### `\u003cSolidColorItem/\u003e`\nThe `SolidColorItem` component renders a gallery item with a solid color material.\nIt accepts a `color` prop to specify the color of the item.\n\nThis component is useful for creating simple gallery items with solid colors.\nIt does not require any additional setup or configuration.\nIf you need more control over the appearance of the gallery item, you can use the `GalleryItem` component with a custom material.\n\n#### Props\n```tsx\ntype SolidColorItemProps = Omit\u003cGalleryItemProps, \"material\"\u003e \u0026 {\n  /**\n   * The color of the solid color item.\n   */\n  color: ColorRepresentation;\n};\n```\n\n#### Example Usage\n```tsx\nimport { Gallery, GalleryScene, SolidColorItem } from \"react-gallery-3d\";\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cSolidColorItem color=\"red\" /\u003e\n          \u003cSolidColorItem color=\"green\" /\u003e\n          \u003cSolidColorItem color=\"blue\" /\u003e\n          \u003cSolidColorItem color=\"yellow\" /\u003e\n          \u003cSolidColorItem color=\"purple\" /\u003e\n          \u003cSolidColorItem color=\"orange\" /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n![Example Output](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/60ce4990-b031-416b-a11c-0c608163e7a7)\n\n\u003cbr/\u003e\n\n### `\u003cImageItem/\u003e`\nThe `ImageItem` component renders a gallery item with an image (texture) mapped to a material.\nThis component is useful for creating gallery items with images.\n\nIt accepts a `texture` for providing a custom texture for the item.\nIt also accepts a `src` prop for specifying the URL of the image to use as the texture.\n\nUsing the `texture` prop is recommended for better performance and control over how the texture is loaded (using `useTexture` from `@react-three/drei` for example).\n\nOne of `src` or `texture` must be provided to render the image.\n\n#### Props\n```tsx\ntype ImageItemProps = Omit\u003cGalleryItemProps, \"material\"\u003e \u0026 {\n  /**\n   * The image source.\n   * If a texture is provided, this will be ignored.\n   */\n  src?: string;\n\n  /**\n   * The texture to use.\n   * If provided, the src will be ignored.\n   */\n  texture?: Texture;\n\n  /**\n   * The material to use.\n   * If not provided, a new MeshStandardMaterial will be created.\n   */\n  material?: MappableMaterial;\n};\n```\n\n#### Example Usage\n```tsx\nimport { Gallery, GalleryScene, ImageItem } from \"react-gallery-3d\";\nimport { useTexture } from \"@react-three/drei\";\n\nfunction MyGallery() {\n  const textures = useTexture([\n    \"/images/img1.jpg\",\n    \"/images/img2.jpg\",\n    \"/images/img3.jpg\",\n    \"/images/img4.jpg\",\n    \"/images/img5.jpg\",\n    \"/images/img6.jpg\",\n  ]);\n\n  return (\n    \u003cGallery\u003e\n      {textures.map((texture, index) =\u003e (\n        \u003cImageItem key={index} texture={texture} /\u003e\n      ))}\n    \u003c/Gallery\u003e\n  );\n}\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\n        environment={{\n          preset: \"city\",\n        }}\n      \u003e\n        \u003cMyGallery /\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n![Example Output](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/748e3e2c-c044-4a24-ad1a-edc06e5ffe5a)\n\n\u003e **Note** \u003cbr/\u003e\n\u003e - The images are included in the `public` folder of the project.\n\u003e - `useTexture` is used to load the images as textures for better performance.\n\u003e - `useTexture` must be called in a component that is a child of the `Canvas` component from `@react-three/fiber`.\n\u003e - The  `GalleryScene` component is a wrapper around the `Canvas` component.\n\n\u003cbr/\u003e\n\n### `\u003cVideoItem/\u003e`\nThe `VideoItem` component renders a gallery item with a video texture mapped to a material.\nThis component is useful for creating gallery items with videos.\n\nIt accepts a `src` prop for specifying the URL of the video to use as the texture.\nIt also accepts props to control the video playback, such as `autoplay`, `muted`, and `loop`.\n\nWhen `autoplay` is set to `true`, the video will be muted by default. \nThis is a requirement for autoplaying videos in most browsers.\n\n#### Props\n```tsx\ntype VideoItemProps = Omit\u003cGalleryItemProps, \"material\"\u003e \u0026 {\n  /**\n   * The video source.\n   */\n  src: string;\n\n  /**\n   * Whether to autoplay the video.\n   *\n   * If this is set to true, the video will be muted.\n   *\n   * @default true\n   */\n  autoplay?: boolean;\n\n  /**\n   * Whether to mute the video.\n   *\n   * @default true\n   */\n  muted?: boolean;\n\n  /**\n   * Whether to loop the video.\n   *\n   * @default true\n   */\n  loop?: boolean;\n\n  /**\n   * The cross-origin attribute for the video.\n   */\n  crossOrigin?: JSX.IntrinsicElements[\"video\"][\"crossOrigin\"];\n\n  /**\n   * A callback that is called when the video is initialized.\n   * This is useful for getting references to the video and texture.\n   *\n   * @param video the video element\n   * @param texture the video texture\n   */\n  onInit?: (video: HTMLVideoElement, texture: VideoTexture) =\u003e void;\n\n  /**\n   * The material to use for the video.\n   *\n   * If not provided, a new MeshStandardMaterial will be created.\n   */\n  material?: MappableMaterial;\n};\n```\n\n#### Example Usage\n```tsx\nimport { Gallery, GalleryScene, VideoItem } from \"react-gallery-3d\";\n\nfunction App() {\n  const videos = [\n    \"/videos/vid1.mp4\",\n    \"/videos/vid2.mp4\",\n    \"/videos/vid3.mp4\",\n    \"/videos/vid4.mp4\",\n    \"/videos/vid5.mp4\",\n    \"/videos/vid6.mp4\",\n  ];\n\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\n        environment={{\n          preset: \"city\",\n        }}\n        fog={{\n          far: 500,\n        }}\n      \u003e\n        \u003cGallery\u003e\n          {videos.map((video) =\u003e (\n            \u003cVideoItem key={video} src={video} /\u003e\n          ))}\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n![Example Output](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/8985944f-48df-4f5e-8f69-c5ea64e4f915)\n\n\u003e **Note** \u003cbr/\u003e\n\u003e The videos are included in the `public` folder of the project.\n\n\u003cbr/\u003e\n\n### `\u003cTransparentItem/\u003e`\nThe `TransparentItem` component renders a gallery item with a transparent material.\nThis component is useful for creating gallery items with transparent background.\n\nIt is not very useful on its own, but can be combined with other components to create more complex galleries.\n\n#### Props\n```tsx\ntype TransparentItemProps = Omit\u003cGalleryItemProps, \"material\"\u003e \u0026 {\n  /**\n   * The opacity of the item.\n   *\n   * @default 0\n   */\n  opacity?: number;\n};\n```\n\n#### Example Usage\n```tsx\nimport {\n  Gallery,\n  GalleryScene,\n  ImageItem,\n  SolidColorItem,\n  VideoItem,\n  TransparentItem,\n  usePlacementOnGalleryItem,\n} from \"react-gallery-3d\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { Mesh } from \"three\";\n\nfunction GalleryItemBox() {\n  const [size] = useState(10);\n  const boxRef = useRef\u003cMesh\u003e(null!);\n  const { position, orientation } = usePlacementOnGalleryItem(size / 2);\n\n  useEffect(() =\u003e {\n    const box = boxRef.current;\n    box.position.copy(position);\n    box.lookAt(orientation);\n  }, [orientation, position]);\n\n  return (\n    \u003cmesh ref={boxRef}\u003e\n      \u003cboxGeometry args={[size, size, size]} /\u003e\n      \u003cmeshStandardMaterial color=\"white\" /\u003e\n    \u003c/mesh\u003e\n  );\n}\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cImageItem src=\"https://picsum.photos/1280/720\" /\u003e\n\n          \u003cSolidColorItem color=\"teal\" /\u003e\n\n          \u003cTransparentItem /\u003e\n\n          \u003cVideoItem\n            src=\"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\"\n            crossOrigin=\"anonymous\"\n          /\u003e\n\n          \u003cTransparentItem\u003e\n            \u003cGalleryItemBox /\u003e\n          \u003c/TransparentItem\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n![Example Output](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/de1200c1-8077-4330-88b7-584df8e6373e)\n\n\u003e **Note** \u003cbr/\u003e\n\u003e - The image is fetched from an external source (picsum). The image may change each time you reload the page.\n\u003e - The `GalleryItemBox` uses the `usePlacementOnGalleryItem` hook to position the box on the gallery item.\n\n\u003cbr/\u003e\n\n### `\u003cObjectItem/\u003e`\nThe `ObjectItem` component renders a gallery item with a custom three.js object.\nThis component is useful for creating gallery items with custom 3D objects.\n\nIt accepts an `object` prop for specifying the custom object to render.\nBy default, the `object` will be rendered by the component. This is useful for rendering instances of models, meshes, etc.\n\nIf you want to control the rendering of the object, set the `disableObjectRender` prop to `true`. \nThis will automatically align the object on the gallery item surface using the `usePlacementOnGalleryItem` hook\nbut will not render the object.\n\nWhen `disableObjectRender` is set to `true`, the component will not pass the `objectProps` prop to the object.\nThis allows you to render the object yourself and have full control over its appearance and behavior.\n\nThis component makes it very easy render models on gallery items.\nIt can also be used to automatically place an object on a gallery item.\n\n#### Props\n```tsx\ntype ObjectItemProps = TransparentItemProps \u0026 {\n  /**\n   * The object to render.\n   * If null, nothing will be rendered.\n   */\n  object?: Object3D | null;\n\n  /**\n   * The object properties.\n   */\n  objectProps?: Object3DProps;\n\n  /**\n   * The object z-axis offset from the center of the item.\n   */\n  objectOffset?: number;\n\n  /**\n   * The object horizontal alignment offset.\n   */\n  objectAlignmentOffset?: number;\n\n  /**\n   * Whether to disable rendering the object.\n   * This is useful when you want to render the object in a different way.\n   *\n   * When rendering is disabled, the objectProps provided will be ignored.\n   * It becomes your responsibility to render and update the object directly.\n   */\n  disableObjectRender?: boolean;\n\n  /**\n   * A callback that is called when the object alignment changes.\n   * This is useful when you want to update the object alignment after the object is aligned on the item.\n   *\n   * @param object The object that was aligned.\n   */\n  onObjectAlignmentChange?: (object: Object3D) =\u003e void;\n\n  /**\n   * A callback that is called before the object alignment is applied.\n   * This is useful when you want to update the calculated alignment before it is applied.\n   *\n   * @param alignment The calculated object alignment.\n   */\n  onBeforeObjectAlignmentApplied?: (alignment: ObjectAlignment) =\u003e void;\n};\n```\n\n#### Example Usage\n```tsx\nimport { useAnimations, useGLTF } from \"@react-three/drei\";\nimport { useEffect, useState } from \"react\";\nimport {\n  Gallery,\n  GalleryScene,\n  ObjectItem,\n  SolidColorItem,\n} from \"react-gallery-3d\";\nimport { Mesh } from \"three\";\n\nfunction BellyDancer() {\n  const { scene: model, animations } = useGLTF(\"/models/belly-dancer.glb\");\n  const { ref, actions } = useAnimations(animations, model);\n\n  useEffect(() =\u003e {\n    if (actions) {\n      actions[\"Armature|mixamo.com|Layer0\"]?.play();\n    }\n  }, [actions]);\n\n  return (\n    \u003cObjectItem\n      object={model}\n      disableObjectRender\n      onObjectAlignmentChange={(object) =\u003e {\n        object.position.y = -25;\n      }}\n    \u003e\n      \u003cprimitive ref={ref} object={model} scale={[0.5, 0.5, 0.5]} /\u003e\n    \u003c/ObjectItem\u003e\n  );\n}\n\nfunction App() {\n  const [box, setBox] = useState\u003cMesh | null\u003e(null);\n  const { scene: model } = useGLTF(\"/models/low_poly_character_swordsman.glb\");\n\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cObjectItem object={box} objectOffset={0} disableObjectRender\u003e\n            \u003cmesh ref={(boxObj) =\u003e setBox(boxObj)}\u003e\n              \u003cboxGeometry args={[10, 10, 10]} /\u003e\n              \u003cmeshStandardMaterial color=\"white\" /\u003e\n            \u003c/mesh\u003e\n          \u003c/ObjectItem\u003e\n\n          \u003cSolidColorItem color=\"blue\" /\u003e\n\n          \u003cObjectItem\n            object={model}\n            objectProps={{\n              scale: [20, 20, 20],\n            }}\n            onObjectAlignmentChange={(object) =\u003e {\n              object.position.y = -25;\n              object.rotateY(Math.PI);\n            }}\n          /\u003e\n\n          \u003cSolidColorItem color=\"green\" /\u003e\n\n          \u003cBellyDancer /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n![Example Output](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/d03222d7-4d2a-46a2-b43f-3c228b0791ea)\n\n\u003e **Note** \u003cbr/\u003e\n\u003e - The models are included in the `public` folder of the project.\n\u003e - The `BellyDancer` component uses the `useAnimations` and `useGLTF` hooks from `@react-three/drei` to load and animate the model.\n\n\u003cbr/\u003e\n\n## Hooks\n\n### `useGalleryItem()`\nThe `useGalleryItem` hook provides access to the `GalleryItemContext`, allowing you to access the gallery items properties.\n\nThis hook is useful when you need to access the gallery item properties in a child component of the `GalleryItem` component.\nIt returns a `UseGalleryReturnType` object that contains the gallery item properties.\n\n```tsx\ntype UseGalleryItemReturnType = GalleryItemState \u0026 {\n  /**\n   * The total number of items in the gallery.\n   */\n  itemCount: number;\n};\n\ntype GalleryItemState = {\n  /**\n   * The width of the gallery item.\n   */\n  width: number;\n\n  /**\n   * The height of the gallery item.\n   */\n  height: number;\n\n  /**\n   * The number of radial segments.\n   */\n  radialSegments: number;\n\n  /**\n   * The number of height segments.\n   */\n  heightSegments: number;\n\n  /**\n   * The percentage of the outer radius to use as the inner radius.\n   */\n  innerRadiusPercent: number;\n\n  /**\n   * The angle of the section of the gallery item.\n   * This is used to calculate the position of the gallery item.\n   */\n  sectionAngle: number;\n\n  /**\n   * The radius of the gallery item.\n   */\n  outerRadius: number;\n\n  /**\n   * The inner radius of the gallery item.\n   */\n  innerRadius: number;\n\n  /**\n   * The index of the gallery item.\n   */\n  itemIndex: number;\n};\n```\n\n#### Example Usage\n```tsx\nimport {\n  Gallery,\n  GalleryScene,\n  SolidColorItem,\n  useGalleryItem,\n  usePlacementOnGalleryItem,\n} from \"react-gallery-3d\";\nimport { Text } from \"@react-three/drei\";\nimport { useEffect, useRef } from \"react\";\nimport { MathUtils, Mesh } from \"three\";\n\nfunction ItemLabel() {\n  const { itemIndex } = useGalleryItem();\n  const textRef = useRef\u003cMesh | null\u003e(null);\n  const { position, orientation } = usePlacementOnGalleryItem(5);\n\n  useEffect(() =\u003e {\n    const text = textRef.current;\n    if (!text) return;\n\n    text.position.copy(position);\n    text.lookAt(orientation);\n    text.rotateY(MathUtils.degToRad(180));\n  }, [orientation, position]);\n\n  return (\n    \u003cText ref={textRef} fontSize={6} color=\"white\" textAlign=\"center\"\u003e\n      ITEM {itemIndex + 1}\n    \u003c/Text\u003e\n  );\n}\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cSolidColorItem color=\"red\"\u003e\n            \u003cItemLabel /\u003e\n          \u003c/SolidColorItem\u003e\n\n          \u003cSolidColorItem color=\"green\"\u003e\n            \u003cItemLabel /\u003e\n          \u003c/SolidColorItem\u003e\n\n          \u003cSolidColorItem color=\"blue\"\u003e\n            \u003cItemLabel /\u003e\n          \u003c/SolidColorItem\u003e\n\n          \u003cSolidColorItem color=\"yellow\"\u003e\n            \u003cItemLabel /\u003e\n          \u003c/SolidColorItem\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n![Example Result](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/2a67c825-2d61-475a-a0f7-fb0c244714fa)\n\n\u003e **Hints** \u003cbr/\u003e\n\u003e - The `ItemLabel` component uses the `useGallery` hook to access the gallery item properties.\n\u003e - The `usePlacementOnGalleryItem` hook is used to position the text on the gallery item surface.\n\n\u003cbr/\u003e\n\n### `usePlacementOnGalleryItem()`\nThe `usePlacementOnGalleryItem` hook calculates the values required to place an object on a gallery item surface.\n\nYou can pass an `objectOffset` to specify the offset of the object from the center of the gallery item.\n\nYou can also pass `itemAlignmentOffset` to adjust the alignment of the object on the gallery item surface.\nThis will be calculated automatically if you do not provide one.\n\nIt returns an `ObjectAlignment` object that contains the position and orientation of the object:\n\n```tsx\ntype ObjectAlignment = {\n  /**\n   * The calculated position for the object.\n   */\n  position: Vector3;\n\n  /**\n   * The calculated orientation for the object.\n   */\n  orientation: Vector3;\n};\n```\n\n\u003e **Hint** \u003cbr/\u003e\n\u003e Check how the `usePlacementOnGalleryItem` hook is used in the [useGalleryItem example](#example-usage-8).\n\n\u003cbr/\u003e\n\n### `useImageMaterial()`\nThe `useImageMaterial` hook creates a material mapped to an image texture.\nIt is useful for creating custom materials for gallery items with images.\n\nAn existing material can be wrapped using the wrappedMaterial prop.\nThis allows you to create a custom material and use the image texture as the map property.\n\nIf no wrappedMaterial is provided, a new `MeshStandardMaterial` is created.\n\nIf a texture is provided, it is used instead of loading the source:\n```tsx\ntype UseImageMaterialOptions = {\n  /**\n   * The image source.\n   * If a texture is provided, this will be ignored.\n   */\n  src?: string;\n\n  /**\n   * The texture to use.\n   * If provided, the src will be ignored.\n   */\n  texture?: Texture;\n\n  /**\n   * The wrapped material.\n   * If not provided, a new MeshStandardMaterial will be created.\n   */\n  wrappedMaterial?: MappableMaterial;\n};\n```\n\nThe hook returns a `UseImageMaterialReturnType` object that contains the material and texture:\n\n```tsx\ntype UseImageMaterialReturnType = {\n  /**\n   * The texture for the image.\n   */\n  texture: Texture;\n\n  /**\n   * The material for the image.\n   */\n  material: MappableMaterial;\n};\n```\n\n#### Example Usage\n```tsx\nimport {\n  Gallery,\n  GalleryScene,\n  GalleryItem,\n  ImageItemProps,\n  useImageMaterial,\n} from \"react-gallery-3d\";\nimport { useMemo } from \"react\";\nimport { MeshPhysicalMaterial } from \"three\";\n\nfunction GlassImageItem({ src, texture, children }: ImageItemProps) {\n  const material = useMemo(() =\u003e {\n    return new MeshPhysicalMaterial({\n      toneMapped: true,\n      polygonOffset: true,\n      polygonOffsetFactor: 1,\n      polygonOffsetUnits: 1,\n      metalness: 0,\n      roughness: 0,\n      transmission: 0.2,\n      clearcoat: 0.1,\n      transparent: true,\n      opacity: 0.7,\n    });\n  }, []);\n\n  const { material: finalMaterial } = useImageMaterial({\n    src,\n    texture,\n    wrappedMaterial: material,\n  });\n\n  return \u003cGalleryItem material={finalMaterial}\u003e{children}\u003c/GalleryItem\u003e;\n}\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\n        ground={{\n          reflectorMaterial: {\n            metalness: 1,\n            roughness: 0.9,\n            mirror: 1,\n            resolution: 2048,\n          },\n        }}\n        environment={{\n          preset: \"city\",\n        }}\n      \u003e\n        \u003cGallery\u003e\n          \u003cGlassImageItem src=\"/images/img4.jpg\" /\u003e\n          \u003cGlassImageItem src=\"/images/img5.jpg\" /\u003e\n          \u003cGlassImageItem src=\"/images/img6.jpg\" /\u003e\n          \u003cGlassImageItem src=\"/images/img1.jpg\" /\u003e\n          \u003cGlassImageItem src=\"/images/img2.jpg\" /\u003e\n          \u003cGlassImageItem src=\"/images/img3.jpg\" /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n![Example Output](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/11d0bab0-997a-4e4f-b970-6513443d1850)\n\n\u003cbr/\u003e\n\n### `useVideoMaterial()`\nThe `useVideoMaterial` hook creates a material mapped to a video texture.\nIt is useful for creating custom materials for gallery items with videos.\n\nAn existing material can be wrapped using the wrappedMaterial prop.\nThis allows you to create a custom material and use the video texture as the map property.\n\nIf no wrappedMaterial is provided, a new `MeshStandardMaterial` is created:\n```tsx\ntype UseVideoMaterialOptions = {\n  /**\n   * The video source.\n   */\n  src: string;\n\n  /**\n   * The wrapped material.\n   *\n   * If not provided, a new MeshStandardMaterial will be created.\n   */\n  wrappedMaterial?: MappableMaterial;\n\n  /**\n   * Whether to autoplay the video.\n   *\n   * If this is set to true, the video will be muted.\n   *\n   * @default true\n   */\n  autoplay?: boolean;\n\n  /**\n   * Whether to mute the video.\n   *\n   * @default true\n   */\n  muted?: boolean;\n\n  /**\n   * Whether to loop the video.\n   *\n   * @default true\n   */\n  loop?: boolean;\n\n  /**\n   * The cross-origin attribute for the video.\n   */\n  crossOrigin?: JSX.IntrinsicElements[\"video\"][\"crossOrigin\"];\n};\n```\n\nThe hook returns a `UseVideoMaterialReturnType` object that contains the material, video texture, and video element:\n```tsx\ntype UseVideoMaterialReturnType = {\n  /**\n   * The video element.\n   */\n  video: HTMLVideoElement;\n\n  /**\n   * The video texture.\n   */\n  texture: VideoTexture;\n\n  /**\n   * The material.\n   */\n  material: MappableMaterial;\n};\n```\n\n#### Example Usage\n```tsx\nimport {\n  Gallery,\n  GalleryScene,\n  GalleryItem,\n  VideoItemProps,\n  useVideoMaterial,\n} from \"react-gallery-3d\";\nimport { useMemo } from \"react\";\nimport { MeshPhysicalMaterial } from \"three\";\n\nfunction ShinyVideoItem({ children, ...rest }: VideoItemProps) {\n  const material = useMemo(() =\u003e {\n    return new MeshPhysicalMaterial({\n      toneMapped: true,\n      polygonOffset: true,\n      polygonOffsetFactor: 1,\n      polygonOffsetUnits: 1,\n      reflectivity: 1,\n      metalness: 1,\n      roughness: 0.2,\n      clearcoat: 1,\n      clearcoatRoughness: 0.1,\n      emissive: \"#430909\",\n    });\n  }, []);\n\n  const { material: finalMaterial } = useVideoMaterial({\n    ...rest,\n    wrappedMaterial: material,\n  });\n\n  return \u003cGalleryItem material={finalMaterial}\u003e{children}\u003c/GalleryItem\u003e;\n}\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\n        ground={{\n          reflectorMaterial: {\n            metalness: 1,\n            roughness: 0.9,\n            mirror: 1,\n            resolution: 2048,\n          },\n        }}\n        environment={{\n          preset: \"sunset\",\n        }}\n      \u003e\n        \u003cGallery\u003e\n          \u003cShinyVideoItem src=\"/videos/vid4.mp4\" /\u003e\n          \u003cShinyVideoItem src=\"/videos/vid5.mp4\" /\u003e\n          \u003cShinyVideoItem src=\"/videos/vid6.mp4\" /\u003e\n          \u003cShinyVideoItem src=\"/videos/vid1.mp4\" /\u003e\n          \u003cShinyVideoItem src=\"/videos/vid2.mp4\" /\u003e\n          \u003cShinyVideoItem src=\"/videos/vid3.mp4\" /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n![Example Output](https://github.com/isoteriksoftware/react-gallery-3d/assets/50753501/13b31329-0aaa-4e5e-bbde-dbc3adf9820c)\n\n\u003cbr/\u003e\n\n## Breaking Changes\nVersion 2.x.x introduces breaking changes to the API.\n\nThe biggest change is on the material generation API. \nThe library now gives you more control over how and when materials are generated and reused across gallery items.\n\nPlease review the following changes carefully to update your code accordingly:\n- The `GalleryItem` component now requires a `material` prop to specify the material for the gallery item. Previously, the material was created internally using a generator function `itemMaterial` prop. This prop is no longer supported.\n- `GalleryItemMaterial` and its subclasses are no longer available. You should use the `GalleryItem` component with a custom material instead.\n- The `Gallery` component no longer accepts props for managing a `Ground` component. The `Ground` component is now managed internally by the `GalleryScene` component. All the props for the `Ground` are now available in the `GalleryScene` component.\n- The `Gallery` component no longer limits its children to only supported types. This means it will render all of its children unlike in previous versions where unknown children are ignored.\n- `useGallery()` hook is no longer available. You should use the `useGalleryItem()` hook to access the gallery item properties.\n\n\n## Migration Guide\nThis guide will help you migrate from version 1.x.x to version 2.x.x of the library.\n\n### GalleryItem Material API\nIn version 1.x.x, the `GalleryItem` component generated the material internally using the `itemMaterial` prop.\nThis was a convenient way to create materials for gallery items without having to manage them manually.\n\nIn version 2.x.x, the `GalleryItem` component requires a `material` prop to specify the material for the gallery item.\nThis gives you more control over how and when materials are created and reused across gallery items.\n\n#### Before\n```tsx\nclass ShinyRedMaterial implements GalleryItemMaterial {\n  public generate() {\n    return new MeshPhysicalMaterial({\n      color: 'red',\n      reflectivity: 1,\n      metalness: 1,\n      roughness: 0.2,\n      clearcoat: 1,\n      clearcoatRoughness: 0.1,\n      polygonOffsetFactor: 1,\n      polygonOffsetUnits: 1,\n    });\n  }\n}\n\nfunction App() {\n  const shinyRedMaterialGenerator = useMemo(() =\u003e new ShinyRedMaterial(), []);\n  const [shinyRedMaterial, setShinyRedMaterial] = useState\u003cMeshPhysicalMaterial\u003e();\n\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cGalleryItem\n            itemMaterial={shinyRedMaterialGenerator}\n            onInit={({ material }) =\u003e setShinyRedMaterial(material as MeshPhysicalMaterial)}\n          /\u003e\n\n          {/* Other items... */}\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n```\n\n#### Now\n```tsx\nfunction App() {\n  const shinyRedMaterial = useMemo(\n    () =\u003e\n      new MeshPhysicalMaterial({\n        color: \"red\",\n        reflectivity: 1,\n        metalness: 1,\n        roughness: 0.2,\n        clearcoat: 1,\n        clearcoatRoughness: 0.1,\n        polygonOffsetFactor: 1,\n        polygonOffsetUnits: 1,\n      }),\n    [],\n  );\n\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cGalleryItem material={shinyRedMaterial} /\u003e\n\n          {/* Other items... */}\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n```\n\n\u003cbr/\u003e\n\n### GalleryItemMaterial Implementations\nIn version 1.x.x, the library provided `GalleryItemMaterial` and its \nimplementations (`ImageItemMaterial`, `SolidColorItemMaterial`, and `VideoItemMaterial`) to create materials for gallery items.\n\nThese implementations are no longer available in version 2.x.x.\nYou should use the `GalleryItem` component with a custom material or use new hooks like `useImageMaterial()` and \n`useVideoMaterial()` to create materials for gallery items.\n\n#### Before\n```tsx\nclass GlassyImageMaterial extends ImageItemMaterial {\n  constructor() {\n    super(\"/images/img1.jpg\");\n  }\n\n  public generate() {\n    this.initTexture();\n\n    return new MeshPhysicalMaterial({\n      toneMapped: false,\n      map: this.texture,\n      polygonOffset: true,\n      polygonOffsetFactor: 1,\n      polygonOffsetUnits: 1,\n      metalness: 0,\n      roughness: 0,\n      transmission: 0.2,\n      clearcoat: 0.3,\n    });\n  }\n}\n\nfunction App() {\n  const glassyImageMaterialGenerator = useMemo(\n    () =\u003e new GlassyImageMaterial(),\n    [],\n  );\n  const [glassyImageMaterial, setGlassyImageMaterial] =\n    useState\u003cMeshPhysicalMaterial\u003e();\n\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cGalleryItem\n            itemMaterial={glassyImageMaterialGenerator}\n            onInit={({ material }) =\u003e\n              setGlassyImageMaterial(material as MeshPhysicalMaterial)\n            }\n          /\u003e\n\n          {/* Other items... */}\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n```\n\n#### Now\n```tsx\nfunction GlassyImage() {\n  const material = useMemo(() =\u003e {\n    return new MeshPhysicalMaterial({\n      toneMapped: false,\n      polygonOffset: true,\n      polygonOffsetFactor: 1,\n      polygonOffsetUnits: 1,\n      metalness: 0,\n      roughness: 0,\n      transmission: 0.2,\n      clearcoat: 0.3,\n    });\n  }, []);\n\n  const { material: finalMaterial } = useImageMaterial({\n    src: \"/images/img1.jpg\",\n    wrappedMaterial: material,\n  });\n\n  return \u003cGalleryItem material={finalMaterial} /\u003e;\n}\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cGlassyImage /\u003e\n\n          {/* Other items... */}\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n```\n\n\u003e **Hint** \u003cbr/\u003e\n\u003e Import `useImageMaterial` from `react-gallery-3d`.\n\n\u003cbr/\u003e\n\n### Gallery Ground API\nIn version 1.x.x, the `Gallery` component accepted props for managing a `Ground` component.\nThis allowed you to customize the ground material and properties for the gallery.\n\nIn version 2.x.x, the `Gallery` component no longer accepts props for managing a `Ground` component.\nThe `Ground` component is now managed internally by the `GalleryScene` component.\nAll the props for the `Ground` are now available in the `GalleryScene` component.\n\nThis makes it easier to use one `Ground` component for the entire gallery scene.\n\n#### Before\n```tsx\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\n          ground={{\n            reflectorMaterial: {\n              metalness: 1,\n              roughness: 0.9,\n              mirror: 1,\n              resolution: 2048,\n            },\n          }}\n        \u003e\n          {/* Gallery items... */}\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n```\n\n#### Now\n```tsx\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\n        ground={{\n          reflectorMaterial: {\n            metalness: 1,\n            roughness: 0.9,\n            mirror: 1,\n            resolution: 2048,\n          },\n        }}\n      \u003e\n        \u003cGallery\u003e\n          {/* Gallery items... */}\n        \u003c/Gallery\u003e\n\n        \u003cGallery position-x={160}\u003e\n          {/* Gallery items... */}\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n```\n\n\u003e **Hint** \u003cbr/\u003e\n\u003e You can now render multiple `Gallery` components in the `GalleryScene` component, and they will share the same ground.\n\n\u003cbr/\u003e\n\n### Gallery Children\nIn version 1.x.x, the `Gallery` component only rendered children of supported types (e.g., `GalleryItem`, `SolidColorItem`, `ImageItem`, etc.).\n\nIn version 2.x.x, the `Gallery` component no longer limits its children to only supported types.\nThis means it will render all of its children unlike in previous versions where unknown children are ignored.\n\nThis allows you to render any component as a child of the `Gallery` component. \nOnly children that are `GalleryItem` or renders a `GalleryItem` will be treated as gallery items. \n\n#### Before\n```tsx\n\n// THIS WORKS\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\u003e\n        \u003cGallery\u003e\n          \u003cSolidColorItem color=\"red\" /\u003e\n          \u003cSolidColorItem color=\"green\" /\u003e\n          \u003cSolidColorItem color=\"blue\" /\u003e\n          \u003cSolidColorItem color=\"yellow\" /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n\n\n// THIS DOES NOT WORK\n// Gallery cannot determine the type of the children rendered by MyGalleryItems\n// so it has no idea a valid GalleryItem is being rendered\n\nconst MyGalleryItems = () =\u003e {\n  const images = Array.from(\n    { length: 6 },\n    (_, i) =\u003e `./images/img${i + 1}.jpg`,\n  );\n\n  const textures = useTexture(images);\n\n  return textures.map((texture, index) =\u003e (\n    \u003cImageItem key={index} texture={texture} /\u003e\n  ));\n};\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\n        ground={{\n          reflectorMaterial: {\n            metalness: 1,\n            roughness: 0.9,\n            mirror: 1,\n            resolution: 2048,\n          },\n        }}\n        environment={{\n          preset: \"sunset\",\n        }}\n      \u003e\n        \u003cGallery\u003e\n          \u003cMyGalleryItems /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n```\n\n#### Now\n```tsx\n// THIS WORKS\n// Gallery will render all its children\n// ImageItem renders a GalleryItem, so it will be treated as a gallery item\n\nconst MyGalleryItems = () =\u003e {\n  const images = Array.from(\n    { length: 6 },\n    (_, i) =\u003e `./images/img${i + 1}.jpg`,\n  );\n\n  const textures = useTexture(images);\n\n  return textures.map((texture, index) =\u003e (\n    \u003cImageItem key={index} texture={texture} /\u003e\n  ));\n};\n\nfunction App() {\n  return (\n    \u003cmain\n      style={{\n        height: \"100vh\",\n        width: \"100vw\",\n      }}\n    \u003e\n      \u003cGalleryScene\n        ground={{\n          reflectorMaterial: {\n            metalness: 1,\n            roughness: 0.9,\n            mirror: 1,\n            resolution: 2048,\n          },\n        }}\n        environment={{\n          preset: \"sunset\",\n        }}\n      \u003e\n        \u003cGallery\u003e\n          \u003cMyGalleryItems /\u003e\n        \u003c/Gallery\u003e\n      \u003c/GalleryScene\u003e\n    \u003c/main\u003e\n  );\n}\n```\n\n\u003cbr/\u003e\n\n### GalleryItem Properties\nIn version 1.x.x, the `useGallery()` hook was used to access the gallery item properties.\n\nIn version 2.x.x, the `useGallery()` hook is no longer available.\nYou should use the `useGalleryItem()` hook to access the gallery item properties.\n\n#### Before\n```tsx\nfunction ItemLabel() {\n  const {\n    item: { itemIndex },\n  } = useGallery();\n  const textRef = useRef\u003cMesh | null\u003e(null);\n  const { position, orientation } = usePlacementOnGalleryItem(5);\n\n  useEffect(() =\u003e {\n    const text = textRef.current;\n    if (!text) return;\n\n    text.position.copy(position);\n    text.lookAt(orientation);\n    text.rotateY(MathUtils.degToRad(180));\n  }, [orientation, position]);\n\n  return (\n    \u003cText ref={textRef} fontSize={6} color=\"white\" textAlign=\"center\"\u003e\n      ITEM {(itemIndex || 0) + 1}\n    \u003c/Text\u003e\n  );\n}\n```\n\n#### Now\n```tsx\nfunction ItemLabel() {\n  const { itemIndex } = useGalleryItem();\n  const textRef = useRef\u003cMesh | null\u003e(null);\n  const { position, orientation } = usePlacementOnGalleryItem(5);\n\n  useEffect(() =\u003e {\n    const text = textRef.current;\n    if (!text) return;\n\n    text.position.copy(position);\n    text.lookAt(orientation);\n    text.rotateY(MathUtils.degToRad(180));\n  }, [orientation, position]);\n\n  return (\n    \u003cText ref={textRef} fontSize={6} color=\"white\" textAlign=\"center\"\u003e\n      ITEM {itemIndex + 1}\n    \u003c/Text\u003e\n  );\n}\n```\n\n\u003e **Hint** \u003cbr/\u003e\n\u003e Import `useGalleryItem` from `react-gallery-3d`.\n\u003e The `itemIndex` property is never `null` or `undefined`.\n\u003e The `itemIndex` property is now a direct property of the `useGalleryItem()` hook return value.\n\u003e The `useGalleryItem()` can only be used within a child component of the `GalleryItem` component.\n\n## Contributing\nContributions are welcome! Please read our [Code of Conduct](https://github.com/isoteriksoftware/react-gallery-3d/blob/master/CODE_OF_CONDUCT.md) and [Contributing](https://github.com/isoteriksoftware/react-gallery-3d/blob/master/CONTRIBUTING.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisoteriksoftware%2Freact-gallery-3d","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fisoteriksoftware%2Freact-gallery-3d","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisoteriksoftware%2Freact-gallery-3d/lists"}