Skip to content

kayhadrin/threejs-demo

Repository files navigation

3D demo web app

Goal

  • Demo a 3D SPA using your chosen 3D framework
  • Ensure application is responsive and works on standard desktop browsers

The state of 3D web rendering

While many 3D rendering libraries are currently available, my cursory research highlighted the following contenders:

  1. three.js
  2. Babylon.js, 24K stars on Github
  3. PlayCanvas

3D library pros & cons

Name Pros Cons Github ⭐
three.js
- Wide 3D rendering features
- Mature React integration via React Three Fiber (29K⭐)
- Collection of ready-made "plugins" via Drei (9K⭐)
- Continuous historical growth
- Complexity due to low-level graphics API
- No professional support AFAICT
107K⭐
Babylon.js
- Wide 3D rendering features
- 3D Editor
- React-Babylonjs renderer (0.9K⭐ )
- Supported by Microsoft
- Extraneous features due to being a game engine (E.g. physic engine)
- Smaller community than threejs
24K⭐
PlayCanvas
- Wide 3D rendering features
- Comprehensive 3D Editor & Asset tooling
- Online integration via Web Component API or React renderer
- Paid app hosting
- Extraneous features due to being a game engine (E.g. physic engine)
- Much smaller community
10K⭐

All three engines support advanced rendering features like PBR texturing or transparency.

See also this Wikipedia WebGL frameworks comparison table for more info.

npm download trends of babylonjs vs playcanvas vs three.js in the last 5 years

npm download trends of babylonjs vs playcanvas vs three.js in the last 5 years Source

Which 3D library to choose?

It's clear that three.js is the most mature & popular 3D WebGL library out there. It has a large active community providing lots of reusable code samples and, after 11 years of activity, shows no sign of slowing down.

On the other hand, Babylon.js and PlayCanvas are still very potent contenders thanks to their graphic feature completeness and e2e production tooling. But they seem to appeal to a smaller professional audience (e.g. game studios) as they are built & marketed as game engines; which is overkill for most general web applications.

For the purpose of this 3D demo app, I'll use three.js.

Installation

pnpm install
pnpm build --turbo
pnpm start

Open http://localhost:3000 with your browser to see the result.

Preview

Demo preview

Development

It's recommended to use Docker to create a build & run this demo in a container:

# CWD: this git repo
scripts/docker/build_n_dev.sh

You can then run this command in the Docker container:

# start local webserver
pnpm dev

# run test suite
pnpm test

High-level summary of JS modules

JS dependency graph

  • Models:

    • Typescript model definitions of the app schema.
      • Product / DraftProduct: physical product (e.g. a bottle of beer)
      • ContainerTemplate: template of a product container. E.g. Generic bottle
      • ContainerMaterial: physical material category. E.g. plastic, glass, etc...
      • ImageAsset: image asset
      • ModelAsset: 3D model asset
  • DataLayer:

    • Abstraction layer for the backend
    • Provides API to retrieve models asynchronously
      • E.g. get product draft, get product templates
  • ProductEditorPage: an async React Server Component page for Next.js.

    • Renders a layout with a main section containing the ProductEditor component.
    • Passes containerMaterialID and containerTemplateID from URL query params to ProductEditor to render initial product config.
  • ProductEditor:

    • A React component responsible for rendering and managing the product editing UI.
    • Expects an init prop with initial values for containerMaterialID and containerTemplateID.
    • Manages form state (DraftProduct from Models.ts), basic validation, and render logic to display a 3D model for the product.
    • Displays a Share button to facilitate bookmarking the current page state.
  • ProductEditorCanvas:

    • React component dedicated to render a 3D product preview on a UI canvas
    • Target 3D product asset are loaded asynchronously
    • React Three Fiber canvas and Drei components faciliate the following:
      • viewport resizing
      • ThreeJS canvas/object unmounting
  • Lazy3DModels:

    • React component to help load 3D model assets asynchronously.
    • Individual models can be loaded thanks to the React.lazy() API

Known limitations

  • This demo simulates backend connections via an async DataLayer API.
  • Limited Jest unit testing since webGL canvas isn't available by default. Ideally, e2e tests would add better test coverage.
  • Jest --watch feature doesn't detect file changes on Windows + Docker. Just trigger test reruns manually...
  • DataLayer is not fully used yet
  • Default 3D scene & camera settings are still hard-coded in a React component

Known issues

  • When loading the product editor with the beer bottle model by default, the view is occluded because the camera position is inside the bottle.
  • A "Loading..." notification is supposed to appear when the 3D model is being downloaded; but it doesn't always consistently appear
  • Some React warnings appear during Jest unit tests (related to act()) but I still manage to test the main target functionalities. (See src/components/__tests__/ProductEditor.test.tsx)

Challenges

  • It was my first time using many of the tools used in this demo: next.js, Tailwind, Three.js & React Three Fiber
    • It took some time setting these up and getting my head around their core APIs
    • Getting a decent understanding of what causes React components to be rendered in SSR/clientside by next.js
  • Challenges with Three.js:
    • Getting a general understanding of the various parts of the three.js 3D modeling concepts (scene, camera, mesh objects)
    • Figuring out how to import and load open-source 3D models in GLTF/GLB format
    • Making a WIP loader indicator for Three.js; it's still unstable at this level

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published