Proton is a lightweight, minimal 3D viewer solution based completely in the browser that gets out of your way - just upload and view! No sign up required, no cookies, and no annoying popups or ads.
The app comes with a few intuitive and very easy-to-use features - these are considered opt-in, which means they are not enabled by default. This ensures that the model can occupy as much of the screen as possible at all times, without an UI elements blocking any details.
- Adjustable camera zoom
- Adjustable model rotation
- Toggable model attributes and statistics
Proton supports a variety of 3D model types, but there are certain extensions that it does not currently have support for. Support may change in the future, and of course, feature requests can be made in a new issue with the feature
tag. The community is free to implement a new loader and create a pull request with their changes. Additionally, this list is not exhaustive, and if your model type is not listed here, it's safe to assume it is not supported.
3D Model Type | Supported |
---|---|
.OBJ (Wavefront OBJ file ) | ✔️ |
.PLY (Polygon file format) | ✔️ |
.GLTF (Khronos GTLF file) | ✔️ |
.STL (Stereolithography file) | ✔️ |
.GLB (Khronos GLTF binary file) | ✔️ |
.FBX (Autodesk FBX file) | ✔️ |
.3DM (Rhino 3DM file) | ✔️ |
.3DS (3D Studio file) | ❌ |
.DAE (Collada file) | ❌ |
.BIM (Dotbim file) | ❌ |
.3MF (3D Manufacturing file) | ❌ |
Proton is built using Vue and Typescript, and is bundled using Vite. For deployment, a Cloud Build trigger is activated on any action to the main
branch (pull request, commit, etc.); the trigger builds the project and deploys the compiled static build files to an App Engine instance - the instance initializes an Express server, which serves back the app to the client.
git clone https://github.com/RunItBack1127/Proton3DViewer.git Proton3DViewer
git clone git@github.com:RunItBack1127/Proton3DViewer.git Proton3DViewer
yarn dev
In the Google Cloud environment, an Express server is instantiated that serves the compiled index.html
file back to the client. To initialize the Express server instead, use
yarn run start
An NGINX middleware is provisioned in front of the web app in the Docker environment, similar to how the app is deployed in the App Engine environment.
docker-compose build
docker-compose up --remove-orphans --force-recreate
docker-compose down -v
Proton delegates to the loaders defined in the Three.js library for parsing mesh geometry. Each 3D model type is represented by its respective 3D model wrapper class (e.g. OBJLoader
, GLTFLoader
, etc.).
All of the loaders implemented in Proton inherit baseline functionality from the CustomLoader
class. In this base class, the FileReader
browser API is used to read the contents of the 3D model file as uploaded by the user, and this data (read as binary, plaintext, etc.) is then passed to an associated Three.js loader to be parsed and displayed. Each custom loader class needs to implement the following abstract functionality of the CustomLoader
:
-
loadFileContents()
- this method is passed aFileReader
and aFile
to be read by the reader; all custom loaders need to define how the file will be read by the reader, i.e. as plaintext, as binary or as an array buffer (typically, 3D model formats will delegate to use one of the latter) -
onFinished()
- passed the contents of theFileReader
as determined byloadFileContents()
; this will invoke theparse()
method of the associated Three.js loader and pass the createdObject3D
to theonComplete
method, which will display the model on the frontend
// Sibling abstract loader class to CustomLoader - simply defines that
// the PLY file will be read as an ArrayBuffer using the FileReader API
import { ArrayBufferCustomLoader } from "./CustomLoader";
import { GLTFLoader as THREE_GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
class GLTFLoader extends ArrayBufferCustomLoader {
constructor() {
super( new THREE_GLTF() );
}
onFinished(result: string | ArrayBuffer | null): void {
const loader = this.getLoader() as THREE_GLTF;
// Three.js GLTFLoader expects 4 arguments - we pass the onComplete as
// the 3rd argument; this will display the model on the screen
// (modelScene.scene is an Object3D)
loader.parse( result as ArrayBuffer, "", ( modelScene ) => {
this.onComplete( modelScene.scene );
}, this.onError );
}
onError(error: ErrorEvent): void {
console.error( error );
}
}
export { GLTFLoader };
import { PLYLoader as THREE_PLY } from 'three/examples/jsm/loaders/PLYLoader';
// Sibling abstract loader class to CustomLoader - simply defines that
// the PLY file will be read as an ArrayBuffer using the FileReader API
import { ArrayBufferCustomLoader } from './CustomLoader';
class PLYLoader extends ArrayBufferCustomLoader {
constructor() {
super( new THREE_PLY() );
}
onFinished(result: string | ArrayBuffer | null): void {
const loader = this.getLoader() as THREE_PLY;
// NOTE: Edge case - the parse() method for Three.js PLYLoader does
// not return an Object3D, so we create one with a white material
// (all loaders can do this as it is defined in the CustomLoader
// abstract class)
const bufferGeometry = loader.parse( result as ArrayBuffer );
const model = super.createMesh( bufferGeometry );
// Display the Object3D on the canvas
this.onComplete( model );
}
}
export { PLYLoader };
More examples can be seen in the loaders source code.
- The absolute OG - has a lot more support and maturity than this project, so if you can't view your specific file type here, then your best bet is definitely over there.