{"id":13653414,"url":"https://github.com/sghall/react-vertex","last_synced_at":"2025-05-15T18:07:47.124Z","repository":{"id":40005146,"uuid":"186543046","full_name":"sghall/react-vertex","owner":"sghall","description":":black_medium_small_square: React Vertex | Hooks-based WebGL library for React","archived":false,"fork":false,"pushed_at":"2023-01-07T05:38:37.000Z","size":4162,"stargazers_count":1239,"open_issues_count":13,"forks_count":24,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-02T14:03:27.628Z","etag":null,"topics":["react","react-hooks","webgl"],"latest_commit_sha":null,"homepage":"https://react-vertex.com","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/sghall.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-14T04:12:11.000Z","updated_at":"2025-03-03T15:33:36.000Z","dependencies_parsed_at":"2023-02-06T13:01:02.041Z","dependency_job_id":null,"html_url":"https://github.com/sghall/react-vertex","commit_stats":null,"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sghall%2Freact-vertex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sghall%2Freact-vertex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sghall%2Freact-vertex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sghall%2Freact-vertex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sghall","download_url":"https://codeload.github.com/sghall/react-vertex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247755560,"owners_count":20990620,"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":["react","react-hooks","webgl"],"created_at":"2024-08-02T02:01:10.154Z","updated_at":"2025-04-08T00:36:28.331Z","avatar_url":"https://github.com/sghall.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","React","JavaScript"],"sub_categories":[],"readme":"# React Vertex\n\nHooks-based WebGL library for React\n\n**This library is experimental.**\n\n`npm install @react-vertex/core`\n\nI started working on this to try out hooks and learn more about WebGL. It quickly got out of hand. There's a lot to do still.\n\n### [Documentation and Examples](https://react-vertex.com)\n\nAll the demos on the site are in the [demos folder](https://github.com/sghall/react-vertex/tree/master/demos)\n\n### What's been built\n\n- Scene renderer using React Reconciler\n- Scene graph which handles matrix multiplication\n- Basic lighting system (only point lights so far)\n- Orbit camera and controls\n- Hooks for geometries and materials\n- Dat Gui like dev controls and scene helpers\n\n### CodeSandbox\n\nKeep in mind these sandboxes run in \"development\" mode and, just like for React, that makes a significant difference in performance for this library.\n\n- [Sphere of Spheres](https://codesandbox.io/s/react-vertex-sphere-of-spheres-jn073?fontsize=14) - Basic scene with Phong shading and a single point light.\n- [Sphere Wireframe](https://codesandbox.io/s/react-vertex-sphere-wireframe-qbvlv?fontsize=14) - Simple sphere wireframe example with axes.\n- [Starter Sandbox](https://codesandbox.io/s/react-vertex-starter-2psb2?fontsize=14) - Starter sandbox with axes.\n\n#### Packages:\n\n### @react-vertex/core\n\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/sghall/react-vertex/blob/master/packages/core/LICENSE)\n[![bundlephobia](https://badgen.net/bundlephobia/minzip/@react-vertex/core)](https://bundlephobia.com/result?p=@react-vertex/core)\n[![npm version](https://img.shields.io/npm/v/@react-vertex/core.svg)](https://www.npmjs.com/package/@react-vertex/core)\n\nReact components, renderer and hooks for React Vertex.\n\n`npm install @react-vertex/core`\n\n##### [Documentation for Core](https://react-vertex.com/docs-core-hooks/)\n\n### @react-vertex/geometry-hooks\n\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/sghall/react-vertex/blob/master/packages/geometry-hooks/LICENSE)\n[![bundlephobia](https://badgen.net/bundlephobia/minzip/@react-vertex/geometry-hooks)](https://bundlephobia.com/result?p=@react-vertex/geometry-hooks)\n[![npm version](https://img.shields.io/npm/v/@react-vertex/geometry-hooks.svg)](https://www.npmjs.com/package/@react-vertex/geometry-hooks)\n\nReact hooks for working with geometries in React Vertex.\n\n`npm install @react-vertex/geometry-hooks`\n\n##### [Documentation for Geometry Hooks](https://react-vertex.com/docs-geometry-hooks/)\n\n### @react-vertex/material-hooks\n\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/sghall/react-vertex/blob/master/packages/material-hooks/LICENSE)\n[![bundlephobia](https://badgen.net/bundlephobia/minzip/@react-vertex/material-hooks)](https://bundlephobia.com/result?p=@react-vertex/material-hooks)\n[![npm version](https://img.shields.io/npm/v/@react-vertex/material-hooks.svg)](https://www.npmjs.com/package/@react-vertex/material-hooks)\n\nReact hooks for working with materials in React Vertex.\n\n`npm install @react-vertex/material-hooks`\n\n##### [Documentation for Material Hooks](https://react-vertex.com/docs-material-hooks/)\n\n### @react-vertex/math-hooks\n\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/sghall/react-vertex/blob/master/packages/math-hooks/LICENSE)\n[![bundlephobia](https://badgen.net/bundlephobia/minzip/@react-vertex/math-hooks)](https://bundlephobia.com/result?p=@react-vertex/math-hooks)\n[![npm version](https://img.shields.io/npm/v/@react-vertex/math-hooks.svg)](https://www.npmjs.com/package/@react-vertex/math-hooks)\n\nReact hooks for working with vectors and matrices in React Vertex. Almost all of this is gl-matrix so this adds very little to your bundle. The core also relies on gl-matrix.\n\n`npm install @react-vertex/math-hooks`\n\n##### [Documentation for Math Hooks](https://react-vertex.com/docs-matrix-hooks/)\n\n### @react-vertex/orbit-camera\n\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/sghall/react-vertex/blob/master/packages/orbit-camera/LICENSE)\n[![bundlephobia](https://badgen.net/bundlephobia/minzip/@react-vertex/orbit-camera)](https://bundlephobia.com/result?p=@react-vertex/orbit-camera)\n[![npm version](https://img.shields.io/npm/v/@react-vertex/orbit-camera.svg)](https://www.npmjs.com/package/@react-vertex/orbit-camera)\n\nReact hooks for a basic orbit camera and controls. Almost all of this is gl-matrix so this adds very little to your bundle. The core also relies on gl-matrix.\n\n`npm install @react-vertex/orbit-camera`\n\n##### [Documentation for Orbit Camera](https://react-vertex.com/docs-orbit-camera/)\n\n## How does it work?\n\nInside of a `\u003cCanvas /\u003e` component you are no longer building an HTML document. Instead, a React Vertex scene is built of four primary elements: `\u003ccamera\u003e`, `\u003cgroup\u003e`, `\u003cmaterial\u003e` and `\u003cgeometry\u003e`. You use the elements to build up the WebGL state used by the renderer.\n\nAt its most simple, a scene would look like:\n\n```jsx\n\u003ccamera\u003e\n  \u003cmaterial\u003e\n    \u003cgeometry /\u003e\n  \u003c/material\u003e\n\u003c/camera\u003e\n```\n\nOr something like:\n\n```jsx\n\u003ccamera\u003e\n  \u003cgroup\u003e\n    \u003cmaterial\u003e\n      \u003cgroup\u003e\n        \u003cgeometry /\u003e\n        \u003cgeometry /\u003e\n        \u003cgeometry /\u003e\n      \u003c/group\u003e\n    \u003c/material\u003e\n    \u003cmaterial\u003e\n      \u003cgroup\u003e\n        \u003cmaterial\u003e\n          \u003cgeometry /\u003e\n        \u003c/material\u003e\n        \u003cgeometry /\u003e\n        \u003cgeometry /\u003e\n      \u003c/group\u003e\n    \u003c/material\u003e\n  \u003c/group\u003e\n\u003c/camera\u003e\n```\n\nOf course, you can create your own custom components to build up that document however you like:\n\n```jsx\n\u003ccamera\u003e\n  \u003cgroup\u003e\n    \u003cAsteroids /\u003e\n    \u003cRobots /\u003e\n    {showSharks ? (\n      \u003cgroup\u003e\n        \u003cShark weapon={laserBeam} /\u003e\n        \u003cShark weapon={laserBeam} /\u003e\n      \u003c/group\u003e\n    ) : null}\n  \u003c/group\u003e\n  \u003cSeaBass illTempered={true} /\u003e\n\u003c/camera\u003e\n```\n\n### `\u003ccamera\u003e`\n\nThe camera takes just two props that define the `view` (matrix) and the `projection` (matrix):\n\n```jsx\n\u003ccamera view={view} projection={projection}\u003e\n  \u003cmaterial\u003e\n    \u003cgeometry /\u003e\n    \u003cgeometry /\u003e\n    \u003cgeometry /\u003e\n  \u003c/material\u003e\n\u003c/camera\u003e\n```\n\nThe `view` and `projection` should be instances of [gl-matrix mat4](http://glmatrix.net/docs/module-mat4.html). If you already know how to work with `gl-matrix` then you can use whatever method you like to keep those props up to date. You can mutate the matrices and the changes will be reflected in the render.\n\nFor convenience you can use `@react-vertex/math-hooks` to create a static camera view:\n\n```js\nimport {\n  useInvertedMatrix,\n  usePerspectiveMatrix,\n} from '@react-vertex/math-hooks'\n\nfunction Scene() {\n  const view = useInvertedMatrix(0, 0, 50)\n  const projection = usePerspectiveMatrix(35, 1.0, 0.1, 1000)\n\n  ...\n\n  return (\n    \u003ccamera view={view} projection={projection}\u003e\n      ...\n    \u003c/camera\u003e\n  )\n```\n\nOr use `@react-vertex/orbit-camera` to create a dynamic camera:\n\n```js\nimport { useOrbitCamera, useOrbitControls } from '@react-vertex/orbit-camera'\nimport { useCanvasSize } from '@react-vertex/core'\n\nfunction Scene() {\n  const { width, height } = useCanvasSize()\n\n  const camera = useOrbitCamera(55, width / height, 1, 5000)\n  useOrbitControls(camera)\n\n  ...\n\n  return (\n    \u003ccamera view={camera.view} projection={camera.projection}\u003e\n      ...\n    \u003c/camera\u003e\n  )\n```\n\n### `\u003cmaterial\u003e`\n\nRight now, the material nodes just take a single `program` prop. The `program` is a WebGL program returned from a hook. The nearest `\u003ccamera\u003e` ancestor will define the view and projection. The renderer will set `viewMatrix`, `modelMatrix` and `projectionMatrix` uniforms in the program shaders. You can use `@react-vertex/material-hooks` for some common programs or look at the source to compose your own custom program hooks. The Phong and Lambert programs in `@react-vertex/material-hooks` make use of lights in the scene.\n\n```js\nimport React from 'react'\nimport PropTypes from 'prop-types'\nimport { useHex } from '@react-vertex/color-hooks'\nimport { useSphereElements } from '@react-vertex/geometry-hooks'\nimport { useBasicSolid } from '@react-vertex/material-hooks'\n\nfunction Example({ position }) {\n  const sphere = useSphereElements(0.75, 10, 10)\n  const diffuse = useHex('#ffa500', true)\n  const program = useBasicSolid(diffuse)\n\n  return (\n    \u003cmaterial program={program}\u003e\n      \u003cgeometry position={position} {...sphere} /\u003e\n    \u003c/material\u003e\n  )\n}\n\nExample.propTypes = {\n  position: PropTypes.array.isRequired,\n}\n\nexport default Example\n```\n\n### `\u003cgeometry\u003e`\n\nThe `\u003cgeometry\u003e` element defines the attributes and several other parameters for drawing. You can also set the `position`, `rotation` and `scale`. The nearest `\u003cmaterial\u003e` ancestor will define what program is applied to the geometries. Probably, the easiest way to get started is to use the hooks from `@react-vertex/geometry-hooks`.\n\n```js\nimport React from 'react'\nimport { useVector3 } from '@react-vertex/math-hooks'\nimport { useBoxElements } from '@react-vertex/geometry-hooks'\n\nconst PI = Math.PI\n\nfunction Boxes() {\n  const boxElements = useBoxElements(10, 10, 10)\n\n  const r1 = useVector3(PI / 4, PI, 0)\n\n  const p1 = useVector3(10, 0, 0)\n  const p2 = useVector3(20, 0, 0)\n  const p3 = useVector3(30, 0, 0)\n  const p4 = useVector3(40, 0, 0)\n\n  return (\n    \u003cgroup rotation={r1}\u003e\n      \u003cgeometry position={p1} {...boxElements} /\u003e\n      \u003cgeometry position={p2} {...boxElements} /\u003e\n      \u003cgeometry position={p3} {...boxElements} /\u003e\n      \u003cgeometry position={p4} {...boxElements} /\u003e\n    \u003c/group\u003e\n  )\n}\n```\n\nTo get more control over the geometry buffers and attributes you can use some of the more low-level hooks from the `@react-vertex/core`:\n\n```js\nimport React, { Fragment, useMemo } from 'react'\nimport { useVector3 } from '@react-vertex/math-hooks'\nimport { useBoxGeometry } from '@react-vertex/geometry-hooks'\nimport {\n  useWebGLContext,\n  useStaticBuffer,\n  useAttribute,\n} from '@react-vertex/core'\n\nfunction Boxes() {\n  const geometry = useBoxGeometry(10, 10, 10)\n\n  // this is what \"useBoxElements\" does internally...\n  const gl = useWebGLContext()\n\n  const positionBuffer = useStaticBuffer(gl, geometry.vertices, false, 'F32')\n  const position = useAttribute(gl, 3, positionBuffer)\n\n  const normalBuffer = useStaticBuffer(gl, geometry.normals, false, 'F32')\n  const normal = useAttribute(gl, 3, normalBuffer)\n\n  const uvBuffer = useStaticBuffer(gl, geometry.uvs, false, 'F32')\n  const uv = useAttribute(gl, 2, uvBuffer)\n\n  const indexBuffer = useStaticBuffer(gl, geometry.indices, true, 'U16')\n\n  const boxElements = useMemo(\n    () =\u003e ({\n      index: indexBuffer,\n      attributes: { position, normal, uv },\n      drawElements: { mode: 'TRIANGLES', count: geometry.indices.length },\n    }),\n    [indexBuffer, geometry.indices.length, position, normal, uv],\n  )\n\n  const r1 = useVector3(PI / 4, PI, 0)\n\n  const p1 = useVector3(10, 0, 0)\n  const p2 = useVector3(20, 0, 0)\n  const p3 = useVector3(30, 0, 0)\n  const p4 = useVector3(40, 0, 0)\n\n  return (\n    \u003cgroup rotation={r1}\u003e\n      \u003cgeometry position={p1} {...boxElements} /\u003e\n      \u003cgeometry position={p2} {...boxElements} /\u003e\n      \u003cgeometry position={p3} {...boxElements} /\u003e\n      \u003cgeometry position={p4} {...boxElements} /\u003e\n    \u003c/group\u003e\n  )\n}\n```\n\n## Rendering\n\n**By default nothing will be rendered.** You can set the `renderOnUpdate` prop on the `Canvas` component to true to have it work something like a regular react component tree. If the scene has lots of elements or is animating constantly it's going to make more sense to render it in more controlled way with the `useRender` hook.\n\n### Rendering in a loop\n\nYou can get a function to render the scene by calling `useRender` anywhere in a React Vertex component tree. If your scene is animating constantly, it's probably best to have one loop right at the root of the tree that renders on each frame. You can use `d3-timer` to create a loop like so:\n\n```js\nimport React, { useEffect } from 'react'\nimport { timer } from 'd3-timer'\nimport { useRender } from '@react-vertex/core'\n\nfunction Scene() {\n  const renderScene = useRender()\n\n  useEffect(() =\u003e {\n    const timerLoop = timer(renderScene)\n    return () =\u003e timerLoop.stop()\n  }, [renderScene])\n\n  ...\n```\n\n### Rendering when camera updates\n\nIf you want to render when the camera moves. You can do something like the below example. If you look at the \"Tuna Wireframe\" example, it updates when the camera changes and ALSO sets the `renderOnUpdate` prop on the canvas to true to make sure it renders when the controls in the scene update. If you are creating more of an app that has less frequent state updates and mainly responding to user input that's a pretty efficient way to approach it.\n\n```js\nimport React, { useEffect } from 'react'\nimport { useRender, useCanvasSize } from '@react-vertex/core'\nimport { useOrbitCamera, useOrbitControls } from '@react-vertex/orbit-camera'\n\nfunction Scene() {\n  const { width, height } = useCanvasSize()\n\n  const renderScene = useRender()\n\n  const camera = useOrbitCamera(55, width / height, 1, 5000)\n  useOrbitControls(camera)\n\n  useEffect(() =\u003e {\n    renderScene()\n    camera.addListener(renderScene)\n    return () =\u003e camera.removeListener(renderScene)\n  }, [camera, renderScene])\n\n  ...\n```\n\n## Running the repo locally\n\nYou must have `Yarn` (currently version 1.22.4) installed to run the repo.\n\n```\ngit clone git@github.com:sghall/react-vertex.git\ncd react-vertex\nyarn install\nnpx lerna bootstrap\nnpx lerna run docs:dev\n```\n\nGo to http://localhost:3000/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsghall%2Freact-vertex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsghall%2Freact-vertex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsghall%2Freact-vertex/lists"}