Skip to content

Instantly share code, notes, and snippets.

@mathdoodle
Last active July 7, 2020 18:53
Show Gist options
  • Save mathdoodle/c47a5d7db65c7897ef34f657398a777b to your computer and use it in GitHub Desktop.
Save mathdoodle/c47a5d7db65c7897ef34f657398a777b to your computer and use it in GitHub Desktop.
three.js ParametricGeometry

Getting Started with STEMCstudio

Overview

This brief example demonstrates some Best Practices for developing your programs:

  • Modularity,
  • Documentation, and
  • Unit Testing.

It also explains how the various files work together.

For information on specific libraries, e.g. WebGL Graphics and Geometric Algebra, please see the examples and consult the links in the Properties menu.

Modularity

It is extremely beneficial to be able to split your application or library into multiple files, each with a cohesive purpose. Up until recently, re-assembling them in JavaScript was error prone because of the need to manually manage file dependencies. But no more! The ES6 modules specification allows you to easily describe the dependencies between the modules that comprise your application so that the system-wide module loader, System can load them strictly according to their dependencies.

Documentaion

Documentation of your software can take many forms. STEMCstudio supports the Markdown format making it easy to create application- or library-level documentation. The contents of the README.md file, transpiled to HTML, are displayed while your application is not running. The README.md file is also a prominent artifact in GitHub.

Unit Testing

Unit Testing is supported using Jasmine.

How It Works

index.html

You may define many views in one project, but this file is recognized by name as the default view.

Your ES6 modules are inserted at the // CODE-MARKER.

Importing your top-level module, e.g. index.js using

System.import('./index.js')

will begin the execution of your program.

The System module loader will manage dependencies for you through import and export statements.

index.ts

Notice how it imports its dependencies and how they are exported from other files.

style.css

The contents of this file are inserted into index.html at the /* STYLE-MARKER */.

Dependencies

External dependencies are defined using the Properties menu and are included as <script> elements at the <!--- SCRIPTS-MARKER -->.

You may add other external dependencies directly to the index.html file.

README.md

Refer to the README.md file to see how the following HTML was created.

#h1 ##h2 ###h3 ####h4

emphasis

bold

code

MathJax: \[\nabla M \ne 0\]

Copyright (c) 2016 David Geo Holmes.

export default function() {
describe("...", function() {
it("should ...", function() {
expect(true).toBeTruthy()
})
})
}
<!DOCTYPE html>
<html>
<head>
<!-- STYLES-MARKER -->
<style>
/* STYLE-MARKER */
</style>
<script src='https://jspm.io/system.js'></script>
<!-- SHADERS-MARKER -->
<!-- SCRIPTS-MARKER -->
</head>
<body>
<script>
// CODE-MARKER
</script>
<script>
DomReady.ready(function() {
System.import('./index.js')
});
</script>
<div id='container' style='position: absolute; left: 0px; top: 0px;'></div>
</body>
</html>
import windowResize from './windowResize'
import TrackballControls from './TrackballControls'
import { Scene, PerspectiveCamera, WebGLRenderer } from 'three'
const fov = 45
const screenWidth = window.innerWidth
const screenHeight = window.innerHeight
const aspect = screenWidth / screenHeight
const near = 0.1
const far = 20000
const scene = new Scene()
const camera = new PerspectiveCamera(fov, aspect, near, far)
scene.add(camera)
camera.position.set(0, 150, 400)
camera.lookAt(scene.position)
const renderer = new WebGLRenderer()
renderer.setSize(screenWidth, screenHeight)
const container = document.getElementById('container') as HTMLDivElement
container.appendChild(renderer.domElement)
windowResize(renderer, camera)
// We could setup a fullscreen handler here too...
/* const controls =*/ new TrackballControls(camera, renderer.domElement)
function render() {
requestAnimationFrame(render)
}
requestAnimationFrame(render)
{
"description": "three.js ParametricGeometry",
"dependencies": {
"DomReady": "1.0.0",
"stats.js": "0.16.0",
"jasmine": "3.4.0",
"three": "0.117.1"
},
"name": "",
"version": ""
}
body {
background-color: white;
}
<!DOCTYPE html>
<html>
<head>
<!-- STYLES-MARKER -->
<style>
/* STYLE-MARKER */
</style>
<script src='https://jspm.io/system.js'></script>
<!-- SCRIPTS-MARKER -->
</head>
<body>
<script>
// CODE-MARKER
</script>
<script>
System.import('./tests.js')
</script>
</body>
</html>
import Example from './Example.spec'
window['jasmine'] = jasmineRequire.core(jasmineRequire)
jasmineRequire.html(window['jasmine'])
const env = jasmine.getEnv()
const jasmineInterface = jasmineRequire.interface(window['jasmine'], env)
extend(window, jasmineInterface)
const htmlReporter = new jasmine.HtmlReporter({
env: env,
getContainer: function() { return document.body },
createElement: function() { return document.createElement.apply(document, arguments) },
createTextNode: function() { return document.createTextNode.apply(document, arguments) },
timer: new jasmine.Timer()
})
env.addReporter(htmlReporter)
DomReady.ready(function() {
htmlReporter.initialize()
describe("Example", Example)
env.execute()
})
/*
* Helper function for extending the properties on objects.
*/
export default function extend<T>(destination: T, source: any): T {
for (let property in source) {
destination[property] = source[property]
}
return destination
}
import { PerspectiveCamera } from 'three'
export default class TrackballControls {
constructor(_camera: PerspectiveCamera, _element: HTMLCanvasElement) {
}
}
{
"allowJs": true,
"checkJs": true,
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"jsx": "react",
"module": "system",
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"preserveConstEnums": true,
"removeComments": false,
"skipLibCheck": true,
"sourceMap": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"target": "es5",
"traceResolution": true
}
import { Renderer, PerspectiveCamera } from 'three'
// This THREEx helper makes it easy to handle window resize.
// It will update renderer and camera when window is resized.
//
// # Usage
//
// **Step 1**: Start updating renderer and camera
//
// ```var windowResize = THREEx.WindowResize(aRenderer, aCamera)```
//
// **Step 2**: Start updating renderer and camera
//
// ```windowResize.stop()```
// # Code
/**
* Update renderer and camera when the window is resized
*
* @param renderer the renderer to update
* @param camera the camera to update
*/
export default function windowResize(renderer: Renderer, camera: PerspectiveCamera) {
const callback = function() {
// notify the renderer of the size change
renderer.setSize(window.innerWidth, window.innerHeight);
// update the camera
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
// bind the resize event
window.addEventListener('resize', callback, false);
// return .stop() the function to stop watching window resize
return {
/**
* Stop watching window resize
*/
stop: function() {
window.removeEventListener('resize', callback);
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment