Skip to content

Commit 3a265f6

Browse files
committed
add readme etc
1 parent 77cbe8f commit 3a265f6

File tree

3 files changed

+179
-1
lines changed

3 files changed

+179
-1
lines changed

LICENSE

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
(Copyright (c) 2018 Rich Harris
2+
3+
Permission is hereby granted by the authors of this software, to any person, to use the software for any purpose, free of charge, including the rights to run, read, copy, change, distribute and sell it, and including usage rights to any patents the authors may hold on it, subject to the following conditions:
4+
5+
This license, or a link to its text, must be included with all copies of the software and any derivative works.
6+
7+
Any modification to the software submitted to the authors may be incorporated into the software under the terms of this license.
8+
9+
The software is provided "as is", without warranty of any kind, including but not limited to the warranties of title, fitness, merchantability and non-infringement. The authors have no obligation to provide support or updates for the software, and may not be held liable for any damages, claims or other liability arising from its use.)

README.md

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# convert-threejs-to-classes
2+
3+
This is a script for converting the [Three.js codebase](https://github.com/mrdoob/three.js) to ES2015 classes.
4+
5+
It's very bad code — it's not intended to be maintained over time, but rather to convert the codebase once in order to create a pull request.
6+
7+
8+
## Running the converter
9+
10+
* Clone this repo
11+
* Install dependencies with `npm install`
12+
* Run `npm run pull` to fetch the Three.js repo
13+
* `(cd three.js && npm install)` to install Three.js's dependencies
14+
* Run `npm run test` to run the converter and check that the unit tests still pass.
15+
16+
Once that's done, `cd three.js` then:
17+
18+
* `npm run build` to build the bundle
19+
* `npx serve` to serve the site, then visit [localhost:5000/examples](http://localhost:5000/examples) to make sure the examples still work (some of them don't! See below)
20+
* `rm -rf src.original examples.original` to get rid of the original source code that has been replaced
21+
22+
23+
## Why are you doing this?
24+
25+
There are several good reasons to update from functions to classes. Firstly, the resulting bundle is smaller and faster:
26+
27+
| | size | minified | gzipped |
28+
|--------------|---------|----------|---------|
29+
| current | 1104363 | 774528 | 158525 |
30+
| with classes | 1068830 | 738111 | 154331 |
31+
32+
The minified JavaScript is roughly 5% smaller. Profiling shows that there's an even bigger reduction in the time the browser typically spends parsing and evaluating the bundle.
33+
34+
Secondly, they're (arguably!) much nicer — instead of this...
35+
36+
```js
37+
function Path( points ) {
38+
39+
CurvePath.call( this );
40+
41+
// ...
42+
43+
}
44+
45+
Path.prototype = Object.assign( Object.create( CurvePath.prototype ), {
46+
47+
constructor: Path,
48+
49+
setFromPoints: function ( points ) {
50+
51+
// ...
52+
53+
},
54+
55+
// ...
56+
57+
} );
58+
```
59+
60+
...we can do this:
61+
62+
```js
63+
class Path extends CurvePath {
64+
constructor ( points ) {
65+
66+
super();
67+
68+
// ...
69+
70+
}
71+
72+
setFromPoints ( points ) {
73+
74+
// ...
75+
76+
}
77+
78+
// ...
79+
}
80+
```
81+
82+
The intent of the code is much more explicit, and it's just a lot more compact and *neat*.
83+
84+
Classes are also easier to statically analyse than the alternative, which hopefully paves the way for tree-shaking. We're not quite there yet, as there's still a lot of not-quite-idiomatic code in the Three.js codebase which make static analysis tricky. But we can fix that!
85+
86+
87+
## What's broken/missing?
88+
89+
All the tests pass, and almost all the examples continue to work. The ones that *don't* work are broken because with classes you can no longer do this sort of thing (**which would be a breaking change for some Three.js users**):
90+
91+
```js
92+
function ConvexBufferGeometry( points ) {
93+
94+
THREE.BufferGeometry.call( this );
95+
96+
// ...
97+
98+
}
99+
```
100+
101+
Instead, you must make `ConvexBufferGeometry` a subclass of `THREE.BufferGeometry`:
102+
103+
```js
104+
class ConvexBufferGeometry extends THREE.BufferGeometry {
105+
constructor ( points ) {
106+
107+
super();
108+
109+
// ...
110+
111+
}
112+
113+
// ...
114+
}
115+
```
116+
117+
Automatically converting all those cases is tricky. It might be easier just to fix them manually in a second pull request.
118+
119+
Another difference between classes and functions relates to hoisting. Because functions are hoisted to the top of the scope, circular dependencies (such as exist between `Matrix4` and `Vector3`) aren't a huge problem. Classes are not hoisted in the same way, which means that the order of concatenation matters. The cases where this is a problem can easily be fixed manually, but as far as this converter is concerned, the easiest thing is just to leave `Vector3`, `Box3` and `Quaternion` as functions.
120+
121+
122+
## Follow-up work
123+
124+
Aside from fixing the broken examples, there are a few opportunities to tweak the codebase further. For example there are several cases where methods are defined inside IIFEs — presumably a legacy from before the codebase was modularised, when it was important to avoid variable name clashes:
125+
126+
```js
127+
intersectsSphere: ( function () {
128+
129+
var closestPoint = new Vector3();
130+
131+
return function intersectsSphere( sphere ) {
132+
133+
// Find the point on the AABB closest to the sphere center.
134+
this.clampPoint( sphere.center, closestPoint );
135+
136+
// If that point is inside the sphere, the AABB and sphere intersect.
137+
return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
138+
139+
};
140+
141+
} )(),
142+
```
143+
144+
The code above (assigning a method to `Box3`) could instead be written like so:
145+
146+
```js
147+
// at the top of the file
148+
let closestPoint;
149+
150+
// inside the class body
151+
intersectsSphere ( sphere ) {
152+
153+
if (!closestPoint) closestPoint = new Vector3();
154+
155+
// Find the point on the AABB closest to the sphere center.
156+
this.clampPoint( sphere.center, closestPoint );
157+
158+
// If that point is inside the sphere, the AABB and sphere intersect.
159+
return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
160+
161+
}
162+
```
163+
164+
Changing this would allow `Vector3` to become a class rather than a function.
165+
166+
167+
## License
168+
169+
[LIL](LICENSE)

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"preconvert": "npm run build",
88
"build": "rollup -c",
99
"dev": "rollup -cw",
10-
"pull": "rm -rf three.js && git clone git@github.com:mrdoob/three.js.git && cp -r three.js/src three.js/src.original",
10+
"pull": "rm -rf three.js && git clone git@github.com:mrdoob/three.js.git && cp -r three.js/src three.js/src.original && cp -r three.js/examples three.js/examples.original",
1111
"test": "(cd three.js && npm test)",
1212
"pretest": "npm run convert"
1313
},

0 commit comments

Comments
 (0)