Socket
Book a DemoInstallSign in
Socket

@codyjasonbennett/react-ogl

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@codyjasonbennett/react-ogl

A barebones react renderer for OGL.

Source
npmnpm
Version
0.4.3-bundlephobia.0
Version published
Weekly downloads
15
1400%
Maintainers
1
Weekly downloads
 
Created
Source

react-ogl

Version Downloads Twitter Discord

Declaratively create scenes with re-usable OGL components that have their own state and effects and can tap into React's infinite ecosystem.

Installation

npm install ogl react-ogl

What is it?

react-ogl is a barebones react renderer for ogl with an emphasis on minimalism and modularity. Its reconciler simply expresses JSX as ogl elements — <mesh /> becomes new OGL.Mesh(). This happens dynamically; there's no wrapper involved.

How does this compare to @react-three/fiber?

react-ogl is a complete re-architecture of @react-three/fiber with:

  • no defaults; you have complete control. No default renderer, camera, etc. For library/engine authors, this allows components to be completely transformative of rendering behavior and API. But this freedom leads to boilerplate. For both users and authors, there are —
  • extendable helpers; react-ogl exports helper components and hooks for both web and native with an API familiar to @react-three/fiber, but these helpers are also modular. This enables you to change or extend rendering behavior and API while maintaining interop with the react-ogl ecosystem.

The API is the same as @react-three/fiber, but react-ogl is completely modular.

What does it look like?

The following takes complete control and declaratively renders a mesh that can react to state.

import * as OGL from 'ogl'
import { createRoot } from 'react-ogl'

// Init rendering internals
const canvas = document.querySelector('canvas')
const renderer = new OGL.Renderer({ canvas })
const camera = new OGL.Camera(renderer.gl)
camera.position.z = 5
const scene = new OGL.Transform(renderer.gl)

// Set initial size
renderer.setSize(window.innerWidth, window.innerHeight)
camera.perspective({ aspect: window.innerWidth / window.innerHeight })

// Create root
const root = createRoot(canvas, { renderer, camera, scene })
root.render(
  <mesh>
    <box />
    <program
      vertex={`
        attribute vec3 position;
        attribute vec3 normal;

        uniform mat4 modelViewMatrix;
        uniform mat4 projectionMatrix;
        uniform mat3 normalMatrix;

        varying vec3 vNormal;

        void main() {
          vNormal = normalize(normalMatrix * normal);
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
      `}
      fragment={`
        precision highp float;

        uniform vec3 uColor;
        varying vec3 vNormal;

        void main() {
          vec3 normal = normalize(vNormal);
          float lighting = dot(normal, normalize(vec3(10)));

          gl_FragColor.rgb = uColor + lighting * 0.1;
          gl_FragColor.a = 1.0;
        }
      `}
      uniforms={{ uColor: 'white' }}
    />
  </mesh>,
)

// Render to screen
const animate = () => {
  requestAnimationFrame(animate)
  renderer.render({ scene, camera })
}
animate()

react-ogl itself is super minimal, but you can use the familiar @react-three/fiber API with some helpers targeted for different platforms:

Usage with react-dom

This example uses create-react-app for the sake of simplicity, but you can use your own environment or create a codesandbox.

# Create app
npx create-react-app my-app
cd my-app

# Install dependencies
npm install ogl react-ogl

# Start
npm run start

Inside of our app, we can use the same API as @react-three/fiber but with OGL elements and methods.

import { useRef, useState } from 'react'
import { useFrame, Canvas } from 'react-ogl'
import { render } from 'react-dom'

const Box = (props) => {
  const mesh = useRef()
  const [hovered, setHover] = useState(false)
  const [active, setActive] = useState(false)

  useFrame(() => (mesh.current.rotation.x += 0.01))

  return (
    <mesh
      {...props}
      ref={mesh}
      scale={active ? 1.5 : 1}
      onClick={() => setActive((value) => !value)}
      onPointerOver={() => setHover(true)}
      onPointerOut={() => setHover(false)}
    >
      <box />
      <program
        vertex={`
          attribute vec3 position;
          attribute vec3 normal;

          uniform mat4 modelViewMatrix;
          uniform mat4 projectionMatrix;
          uniform mat3 normalMatrix;

          varying vec3 vNormal;

          void main() {
            vNormal = normalize(normalMatrix * normal);
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
          }
        `}
        fragment={`
          precision highp float;

          uniform vec3 uColor;
          varying vec3 vNormal;

          void main() {
            vec3 normal = normalize(vNormal);
            float lighting = dot(normal, normalize(vec3(10)));

            gl_FragColor.rgb = uColor + lighting * 0.1;
            gl_FragColor.a = 1.0;
          }
        `}
        uniforms={{ uColor: hovered ? 'hotpink' : 'orange' }}
      />
    </mesh>
  )
}

render(
  <Canvas camera={{ position: [0, 0, 8] }}>
    <Box position={[-1.2, 0, 0]} />
    <Box position={[1.2, 0, 0]} />
  </Canvas>,
  document.getElementById('root'),
)
Usage with react-native

This example uses expo-cli but you can create a bare app with react-native CLI as well.

# Create app and cd into it
npx expo init my-app # or npx react-native init my-app
cd my-app

# Automatically install & link expo modules
npx install-expo-modules
expo install expo-gl

# Install NPM dependencies
npm install ogl react-ogl

# Start
npm run start

We'll also need to configure metro.config.js to look for the mjs file extension that ogl uses.

module.exports = {
  resolver: {
    sourceExts: ['json', 'js', 'jsx', 'ts', 'tsx', 'cjs', 'mjs'],
    assetExts: ['glb', 'gltf', 'png', 'jpg'],
  },
}

Inside of our app, you can use the same API as web while running on native OpenGL ES — no webview needed.

import React, { useRef, useState } from 'react'
import { useFrame, Canvas } from 'react-ogl'

const Box = (props) => {
  const mesh = useRef()
  const [hovered, setHover] = useState(false)
  const [active, setActive] = useState(false)

  useFrame(() => (mesh.current.rotation.x += 0.01))

  return (
    <mesh
      {...props}
      ref={mesh}
      scale={active ? 1.5 : 1}
      onClick={() => setActive((value) => !value)}
      onPointerOver={() => setHover(true)}
      onPointerOut={() => setHover(false)}
    >
      <box />
      <program
        vertex={`
          attribute vec3 position;
          attribute vec3 normal;

          uniform mat4 modelViewMatrix;
          uniform mat4 projectionMatrix;
          uniform mat3 normalMatrix;

          varying vec3 vNormal;

          void main() {
            vNormal = normalize(normalMatrix * normal);
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
          }
        `}
        fragment={`
          precision highp float;

          uniform vec3 uColor;
          varying vec3 vNormal;

          void main() {
            vec3 normal = normalize(vNormal);
            float lighting = dot(normal, normalize(vec3(10)));

            gl_FragColor.rgb = uColor + lighting * 0.1;
            gl_FragColor.a = 1.0;
          }
        `}
        uniforms={{ uColor: hovered ? 'hotpink' : 'orange' }}
      />
    </mesh>
  )
}

const App = () => (
  <Canvas camera={{ position: [0, 0, 8] }}>
    <Box position={[-1.2, 0, 0]} />
    <Box position={[1.2, 0, 0]} />
  </Canvas>
)

export default App

OGL issues with SSR/Node

OGL doesn't properly label its ESM target, so Node environments won't be able to resolve it correctly. You can fix that with the following, creating a CJS bundle and mending targets:

npx rollup node_modules/ogl/src/index.mjs --file node_modules/ogl/ogl.cjs --format cjs && npx json -I -f node_modules/ogl/package.json -e "this.module=\"./src/index.mjs\";this.main=\"./ogl.cjs\""

This is best to add to a postinstall script or on a fork of https://github.com/oframe/ogl, so changes will persist:

{
  "scripts": {
    "postinstall": "npx rollup node_modules/ogl/src/index.mjs --file node_modules/ogl/ogl.cjs --format cjs && npx json -I -f node_modules/ogl/package.json -e \"this.module=\\\"./src/index.mjs\\\";this.main=\\\"./ogl.cjs\\\"\""
  }
}

Keywords

react

FAQs

Package last updated on 15 Jun 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts