├── .gitignore
├── LICENSE
├── blender
├── gfc 1k.jpg
├── gfc normals.psd
├── gfc roughness metallic.psd
├── gfc5.blend
├── propeller.png
├── propeller.psd
└── uvs.png
├── package-lock.json
├── package.json
├── public
├── HDR
│ ├── nx.hdr
│ ├── ny.hdr
│ ├── nz.hdr
│ ├── px.hdr
│ ├── py.hdr
│ └── pz.hdr
├── audio
│ ├── propeller.aif
│ ├── propeller.mp3
│ ├── propeller.ogg
│ ├── propeller.xmp
│ ├── propeller2.ogg
│ └── propeller2.xmp
├── draco-gltf
│ ├── draco_decoder.js
│ ├── draco_decoder.wasm
│ └── draco_wasm_wrapper.js
├── gfc-hq.glb
├── good-fast-cheap-social.jpg
└── index.html
├── readme.md
└── src
├── App.js
├── audio
├── button-click.mp3
├── button-inactive.mp3
├── propeller.ogg
├── propeller.wav
├── propeller.xmp
├── servo1.mp3
├── servo2.mp3
├── servo3.mp3
├── squeak1.mp3
├── squeak2.mp3
└── squeak3.mp3
├── components
├── About.js
├── About.scss
├── Controls.js
├── Effects.js
├── Environment.js
├── GFCMachine.js
├── Loading.js
├── Loading.scss
├── SoundButton.js
├── SoundButton.scss
├── UI.js
├── UI.scss
├── UISecondary.js
└── UISecondary.scss
├── images
├── arrow-sm.png
├── jon.jpg
└── propeller.png
├── index.js
└── styles.css
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 | blender/gfc main.psd
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Mozilla Public License Version 2.0
2 | ==================================
3 |
4 | 1. Definitions
5 | --------------
6 |
7 | 1.1. "Contributor"
8 | means each individual or legal entity that creates, contributes to
9 | the creation of, or owns Covered Software.
10 |
11 | 1.2. "Contributor Version"
12 | means the combination of the Contributions of others (if any) used
13 | by a Contributor and that particular Contributor's Contribution.
14 |
15 | 1.3. "Contribution"
16 | means Covered Software of a particular Contributor.
17 |
18 | 1.4. "Covered Software"
19 | means Source Code Form to which the initial Contributor has attached
20 | the notice in Exhibit A, the Executable Form of such Source Code
21 | Form, and Modifications of such Source Code Form, in each case
22 | including portions thereof.
23 |
24 | 1.5. "Incompatible With Secondary Licenses"
25 | means
26 |
27 | (a) that the initial Contributor has attached the notice described
28 | in Exhibit B to the Covered Software; or
29 |
30 | (b) that the Covered Software was made available under the terms of
31 | version 1.1 or earlier of the License, but not also under the
32 | terms of a Secondary License.
33 |
34 | 1.6. "Executable Form"
35 | means any form of the work other than Source Code Form.
36 |
37 | 1.7. "Larger Work"
38 | means a work that combines Covered Software with other material, in
39 | a separate file or files, that is not Covered Software.
40 |
41 | 1.8. "License"
42 | means this document.
43 |
44 | 1.9. "Licensable"
45 | means having the right to grant, to the maximum extent possible,
46 | whether at the time of the initial grant or subsequently, any and
47 | all of the rights conveyed by this License.
48 |
49 | 1.10. "Modifications"
50 | means any of the following:
51 |
52 | (a) any file in Source Code Form that results from an addition to,
53 | deletion from, or modification of the contents of Covered
54 | Software; or
55 |
56 | (b) any new file in Source Code Form that contains any Covered
57 | Software.
58 |
59 | 1.11. "Patent Claims" of a Contributor
60 | means any patent claim(s), including without limitation, method,
61 | process, and apparatus claims, in any patent Licensable by such
62 | Contributor that would be infringed, but for the grant of the
63 | License, by the making, using, selling, offering for sale, having
64 | made, import, or transfer of either its Contributions or its
65 | Contributor Version.
66 |
67 | 1.12. "Secondary License"
68 | means either the GNU General Public License, Version 2.0, the GNU
69 | Lesser General Public License, Version 2.1, the GNU Affero General
70 | Public License, Version 3.0, or any later versions of those
71 | licenses.
72 |
73 | 1.13. "Source Code Form"
74 | means the form of the work preferred for making modifications.
75 |
76 | 1.14. "You" (or "Your")
77 | means an individual or a legal entity exercising rights under this
78 | License. For legal entities, "You" includes any entity that
79 | controls, is controlled by, or is under common control with You. For
80 | purposes of this definition, "control" means (a) the power, direct
81 | or indirect, to cause the direction or management of such entity,
82 | whether by contract or otherwise, or (b) ownership of more than
83 | fifty percent (50%) of the outstanding shares or beneficial
84 | ownership of such entity.
85 |
86 | 2. License Grants and Conditions
87 | --------------------------------
88 |
89 | 2.1. Grants
90 |
91 | Each Contributor hereby grants You a world-wide, royalty-free,
92 | non-exclusive license:
93 |
94 | (a) under intellectual property rights (other than patent or trademark)
95 | Licensable by such Contributor to use, reproduce, make available,
96 | modify, display, perform, distribute, and otherwise exploit its
97 | Contributions, either on an unmodified basis, with Modifications, or
98 | as part of a Larger Work; and
99 |
100 | (b) under Patent Claims of such Contributor to make, use, sell, offer
101 | for sale, have made, import, and otherwise transfer either its
102 | Contributions or its Contributor Version.
103 |
104 | 2.2. Effective Date
105 |
106 | The licenses granted in Section 2.1 with respect to any Contribution
107 | become effective for each Contribution on the date the Contributor first
108 | distributes such Contribution.
109 |
110 | 2.3. Limitations on Grant Scope
111 |
112 | The licenses granted in this Section 2 are the only rights granted under
113 | this License. No additional rights or licenses will be implied from the
114 | distribution or licensing of Covered Software under this License.
115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
116 | Contributor:
117 |
118 | (a) for any code that a Contributor has removed from Covered Software;
119 | or
120 |
121 | (b) for infringements caused by: (i) Your and any other third party's
122 | modifications of Covered Software, or (ii) the combination of its
123 | Contributions with other software (except as part of its Contributor
124 | Version); or
125 |
126 | (c) under Patent Claims infringed by Covered Software in the absence of
127 | its Contributions.
128 |
129 | This License does not grant any rights in the trademarks, service marks,
130 | or logos of any Contributor (except as may be necessary to comply with
131 | the notice requirements in Section 3.4).
132 |
133 | 2.4. Subsequent Licenses
134 |
135 | No Contributor makes additional grants as a result of Your choice to
136 | distribute the Covered Software under a subsequent version of this
137 | License (see Section 10.2) or under the terms of a Secondary License (if
138 | permitted under the terms of Section 3.3).
139 |
140 | 2.5. Representation
141 |
142 | Each Contributor represents that the Contributor believes its
143 | Contributions are its original creation(s) or it has sufficient rights
144 | to grant the rights to its Contributions conveyed by this License.
145 |
146 | 2.6. Fair Use
147 |
148 | This License is not intended to limit any rights You have under
149 | applicable copyright doctrines of fair use, fair dealing, or other
150 | equivalents.
151 |
152 | 2.7. Conditions
153 |
154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155 | in Section 2.1.
156 |
157 | 3. Responsibilities
158 | -------------------
159 |
160 | 3.1. Distribution of Source Form
161 |
162 | All distribution of Covered Software in Source Code Form, including any
163 | Modifications that You create or to which You contribute, must be under
164 | the terms of this License. You must inform recipients that the Source
165 | Code Form of the Covered Software is governed by the terms of this
166 | License, and how they can obtain a copy of this License. You may not
167 | attempt to alter or restrict the recipients' rights in the Source Code
168 | Form.
169 |
170 | 3.2. Distribution of Executable Form
171 |
172 | If You distribute Covered Software in Executable Form then:
173 |
174 | (a) such Covered Software must also be made available in Source Code
175 | Form, as described in Section 3.1, and You must inform recipients of
176 | the Executable Form how they can obtain a copy of such Source Code
177 | Form by reasonable means in a timely manner, at a charge no more
178 | than the cost of distribution to the recipient; and
179 |
180 | (b) You may distribute such Executable Form under the terms of this
181 | License, or sublicense it under different terms, provided that the
182 | license for the Executable Form does not attempt to limit or alter
183 | the recipients' rights in the Source Code Form under this License.
184 |
185 | 3.3. Distribution of a Larger Work
186 |
187 | You may create and distribute a Larger Work under terms of Your choice,
188 | provided that You also comply with the requirements of this License for
189 | the Covered Software. If the Larger Work is a combination of Covered
190 | Software with a work governed by one or more Secondary Licenses, and the
191 | Covered Software is not Incompatible With Secondary Licenses, this
192 | License permits You to additionally distribute such Covered Software
193 | under the terms of such Secondary License(s), so that the recipient of
194 | the Larger Work may, at their option, further distribute the Covered
195 | Software under the terms of either this License or such Secondary
196 | License(s).
197 |
198 | 3.4. Notices
199 |
200 | You may not remove or alter the substance of any license notices
201 | (including copyright notices, patent notices, disclaimers of warranty,
202 | or limitations of liability) contained within the Source Code Form of
203 | the Covered Software, except that You may alter any license notices to
204 | the extent required to remedy known factual inaccuracies.
205 |
206 | 3.5. Application of Additional Terms
207 |
208 | You may choose to offer, and to charge a fee for, warranty, support,
209 | indemnity or liability obligations to one or more recipients of Covered
210 | Software. However, You may do so only on Your own behalf, and not on
211 | behalf of any Contributor. You must make it absolutely clear that any
212 | such warranty, support, indemnity, or liability obligation is offered by
213 | You alone, and You hereby agree to indemnify every Contributor for any
214 | liability incurred by such Contributor as a result of warranty, support,
215 | indemnity or liability terms You offer. You may include additional
216 | disclaimers of warranty and limitations of liability specific to any
217 | jurisdiction.
218 |
219 | 4. Inability to Comply Due to Statute or Regulation
220 | ---------------------------------------------------
221 |
222 | If it is impossible for You to comply with any of the terms of this
223 | License with respect to some or all of the Covered Software due to
224 | statute, judicial order, or regulation then You must: (a) comply with
225 | the terms of this License to the maximum extent possible; and (b)
226 | describe the limitations and the code they affect. Such description must
227 | be placed in a text file included with all distributions of the Covered
228 | Software under this License. Except to the extent prohibited by statute
229 | or regulation, such description must be sufficiently detailed for a
230 | recipient of ordinary skill to be able to understand it.
231 |
232 | 5. Termination
233 | --------------
234 |
235 | 5.1. The rights granted under this License will terminate automatically
236 | if You fail to comply with any of its terms. However, if You become
237 | compliant, then the rights granted under this License from a particular
238 | Contributor are reinstated (a) provisionally, unless and until such
239 | Contributor explicitly and finally terminates Your grants, and (b) on an
240 | ongoing basis, if such Contributor fails to notify You of the
241 | non-compliance by some reasonable means prior to 60 days after You have
242 | come back into compliance. Moreover, Your grants from a particular
243 | Contributor are reinstated on an ongoing basis if such Contributor
244 | notifies You of the non-compliance by some reasonable means, this is the
245 | first time You have received notice of non-compliance with this License
246 | from such Contributor, and You become compliant prior to 30 days after
247 | Your receipt of the notice.
248 |
249 | 5.2. If You initiate litigation against any entity by asserting a patent
250 | infringement claim (excluding declaratory judgment actions,
251 | counter-claims, and cross-claims) alleging that a Contributor Version
252 | directly or indirectly infringes any patent, then the rights granted to
253 | You by any and all Contributors for the Covered Software under Section
254 | 2.1 of this License shall terminate.
255 |
256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257 | end user license agreements (excluding distributors and resellers) which
258 | have been validly granted by You or Your distributors under this License
259 | prior to termination shall survive termination.
260 |
261 | ************************************************************************
262 | * *
263 | * 6. Disclaimer of Warranty *
264 | * ------------------------- *
265 | * *
266 | * Covered Software is provided under this License on an "as is" *
267 | * basis, without warranty of any kind, either expressed, implied, or *
268 | * statutory, including, without limitation, warranties that the *
269 | * Covered Software is free of defects, merchantable, fit for a *
270 | * particular purpose or non-infringing. The entire risk as to the *
271 | * quality and performance of the Covered Software is with You. *
272 | * Should any Covered Software prove defective in any respect, You *
273 | * (not any Contributor) assume the cost of any necessary servicing, *
274 | * repair, or correction. This disclaimer of warranty constitutes an *
275 | * essential part of this License. No use of any Covered Software is *
276 | * authorized under this License except under this disclaimer. *
277 | * *
278 | ************************************************************************
279 |
280 | ************************************************************************
281 | * *
282 | * 7. Limitation of Liability *
283 | * -------------------------- *
284 | * *
285 | * Under no circumstances and under no legal theory, whether tort *
286 | * (including negligence), contract, or otherwise, shall any *
287 | * Contributor, or anyone who distributes Covered Software as *
288 | * permitted above, be liable to You for any direct, indirect, *
289 | * special, incidental, or consequential damages of any character *
290 | * including, without limitation, damages for lost profits, loss of *
291 | * goodwill, work stoppage, computer failure or malfunction, or any *
292 | * and all other commercial damages or losses, even if such party *
293 | * shall have been informed of the possibility of such damages. This *
294 | * limitation of liability shall not apply to liability for death or *
295 | * personal injury resulting from such party's negligence to the *
296 | * extent applicable law prohibits such limitation. Some *
297 | * jurisdictions do not allow the exclusion or limitation of *
298 | * incidental or consequential damages, so this exclusion and *
299 | * limitation may not apply to You. *
300 | * *
301 | ************************************************************************
302 |
303 | 8. Litigation
304 | -------------
305 |
306 | Any litigation relating to this License may be brought only in the
307 | courts of a jurisdiction where the defendant maintains its principal
308 | place of business and such litigation shall be governed by laws of that
309 | jurisdiction, without reference to its conflict-of-law provisions.
310 | Nothing in this Section shall prevent a party's ability to bring
311 | cross-claims or counter-claims.
312 |
313 | 9. Miscellaneous
314 | ----------------
315 |
316 | This License represents the complete agreement concerning the subject
317 | matter hereof. If any provision of this License is held to be
318 | unenforceable, such provision shall be reformed only to the extent
319 | necessary to make it enforceable. Any law or regulation which provides
320 | that the language of a contract shall be construed against the drafter
321 | shall not be used to construe this License against a Contributor.
322 |
323 | 10. Versions of the License
324 | ---------------------------
325 |
326 | 10.1. New Versions
327 |
328 | Mozilla Foundation is the license steward. Except as provided in Section
329 | 10.3, no one other than the license steward has the right to modify or
330 | publish new versions of this License. Each version will be given a
331 | distinguishing version number.
332 |
333 | 10.2. Effect of New Versions
334 |
335 | You may distribute the Covered Software under the terms of the version
336 | of the License under which You originally received the Covered Software,
337 | or under the terms of any subsequent version published by the license
338 | steward.
339 |
340 | 10.3. Modified Versions
341 |
342 | If you create software not governed by this License, and you want to
343 | create a new license for such software, you may create and use a
344 | modified version of this License if you rename the license and remove
345 | any references to the name of the license steward (except to note that
346 | such modified license differs from this License).
347 |
348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
349 | Licenses
350 |
351 | If You choose to distribute Source Code Form that is Incompatible With
352 | Secondary Licenses under the terms of this version of the License, the
353 | notice described in Exhibit B of this License must be attached.
354 |
355 | Exhibit A - Source Code Form License Notice
356 | -------------------------------------------
357 |
358 | This Source Code Form is subject to the terms of the Mozilla Public
359 | License, v. 2.0. If a copy of the MPL was not distributed with this
360 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
361 |
362 | If it is not possible or desirable to put the notice in a particular
363 | file, then You may include the notice in a location (such as a LICENSE
364 | file in a relevant directory) where a recipient would be likely to look
365 | for such a notice.
366 |
367 | You may add additional accurate notices of copyright ownership.
368 |
369 | Exhibit B - "Incompatible With Secondary Licenses" Notice
370 | ---------------------------------------------------------
371 |
372 | This Source Code Form is "Incompatible With Secondary Licenses", as
373 | defined by the Mozilla Public License, v. 2.0.
--------------------------------------------------------------------------------
/blender/gfc 1k.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/blender/gfc 1k.jpg
--------------------------------------------------------------------------------
/blender/gfc normals.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/blender/gfc normals.psd
--------------------------------------------------------------------------------
/blender/gfc roughness metallic.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/blender/gfc roughness metallic.psd
--------------------------------------------------------------------------------
/blender/gfc5.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/blender/gfc5.blend
--------------------------------------------------------------------------------
/blender/propeller.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/blender/propeller.png
--------------------------------------------------------------------------------
/blender/propeller.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/blender/propeller.psd
--------------------------------------------------------------------------------
/blender/uvs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/blender/uvs.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "homepage": ".",
3 | "name": "good-fast-cheap",
4 | "version": "1.0.0",
5 | "description": "",
6 | "keywords": [],
7 | "main": "src/index.js",
8 | "dependencies": {
9 | "@material-ui/core": "^4.9.5",
10 | "node-sass": "^4.13.1",
11 | "postprocessing": "6.10.0",
12 | "react": "16.12.0",
13 | "react-dom": "16.12.0",
14 | "react-scripts": "3.4.0",
15 | "react-spring": "^8.0.27",
16 | "react-three-fiber": "4.0.16",
17 | "three": "0.113.2"
18 | },
19 | "devDependencies": {},
20 | "scripts": {
21 | "start": "react-scripts start",
22 | "build": "react-scripts build",
23 | "test": "react-scripts test --env=jsdom",
24 | "eject": "react-scripts eject"
25 | },
26 | "browserslist": [
27 | ">0.2%",
28 | "not dead",
29 | "not ie <= 11",
30 | "not op_mini all"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/public/HDR/nx.hdr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/HDR/nx.hdr
--------------------------------------------------------------------------------
/public/HDR/ny.hdr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/HDR/ny.hdr
--------------------------------------------------------------------------------
/public/HDR/nz.hdr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/HDR/nz.hdr
--------------------------------------------------------------------------------
/public/HDR/px.hdr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/HDR/px.hdr
--------------------------------------------------------------------------------
/public/HDR/py.hdr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/HDR/py.hdr
--------------------------------------------------------------------------------
/public/HDR/pz.hdr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/HDR/pz.hdr
--------------------------------------------------------------------------------
/public/audio/propeller.aif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/audio/propeller.aif
--------------------------------------------------------------------------------
/public/audio/propeller.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/audio/propeller.mp3
--------------------------------------------------------------------------------
/public/audio/propeller.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/audio/propeller.ogg
--------------------------------------------------------------------------------
/public/audio/propeller.xmp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 | Adobe Audition 13.0 (Macintosh)
14 | 2020-03-03T18:35:51-05:00
15 | 2020-03-21T19:15:42-04:00
16 | 2020-03-21T19:15:42-04:00
17 | xmp.iid:96c22832-aca1-4698-8b22-150d70a06464
18 | xmp.did:29069a54-81e7-4420-b2f2-5655f60ec234
19 | xmp.did:3bcc9fb1-277e-4cc3-920d-a7ab9c1b0d08
20 |
21 |
22 |
23 | saved
24 | xmp.iid:3bcc9fb1-277e-4cc3-920d-a7ab9c1b0d08
25 | 2020-03-03T18:35:51-05:00
26 | Adobe Audition 13.0 (Macintosh)
27 | /metadata
28 |
29 |
30 | saved
31 | xmp.iid:df5d6da4-a579-4795-843b-52544dc60be9
32 | 2020-03-03T19:28:37-05:00
33 | Adobe Audition 13.0 (Macintosh)
34 | /metadata
35 |
36 |
37 | converted
38 | from application/xml to audio/x-wav
39 |
40 |
41 | saved
42 | xmp.iid:89e74d18-7a16-4bd4-9a14-7789f8cabeb1
43 | 2020-03-03T19:28:37-05:00
44 | Adobe Audition 13.0 (Macintosh)
45 |
46 |
47 | converted
48 | from application/xml to audio/x-wav
49 |
50 |
51 | saved
52 | xmp.iid:d2d08c20-1bf2-4898-9e16-9731c3278a07
53 | 2020-03-03T19:28:37-05:00
54 | Adobe Audition 13.0 (Macintosh)
55 | /
56 |
57 |
58 | saved
59 | xmp.iid:5f72772a-dd93-4d24-9eba-52106ed7b09f
60 | 2020-03-04T19:47:31-05:00
61 | Adobe Audition 13.0 (Macintosh)
62 | /metadata
63 |
64 |
65 | converted
66 | from audio/x-wav to audio/ogg; codec="vorbis"
67 |
68 |
69 | saved
70 | xmp.iid:ba3f33c3-bb06-419e-927d-2668fc9222aa
71 | 2020-03-04T19:47:31-05:00
72 | Adobe Audition 13.0 (Macintosh)
73 |
74 |
75 | converted
76 | from audio/x-wav to audio/ogg; codec="vorbis"
77 |
78 |
79 | saved
80 | xmp.iid:29069a54-81e7-4420-b2f2-5655f60ec234
81 | 2020-03-04T19:47:31-05:00
82 | Adobe Audition 13.0 (Macintosh)
83 | /
84 |
85 |
86 | saved
87 | xmp.iid:0630047b-f8e0-4c7e-ba6b-0880e74965b1
88 | 2020-03-21T19:15:42-04:00
89 | Adobe Audition 13.0 (Macintosh)
90 | /metadata
91 |
92 |
93 | saved
94 | xmp.iid:96c22832-aca1-4698-8b22-150d70a06464
95 | 2020-03-21T19:15:42-04:00
96 | Adobe Audition 13.0 (Macintosh)
97 | /
98 |
99 |
100 |
101 |
102 | xmp.iid:ba3f33c3-bb06-419e-927d-2668fc9222aa
103 | xmp.did:ba3f33c3-bb06-419e-927d-2668fc9222aa
104 | xmp.did:3bcc9fb1-277e-4cc3-920d-a7ab9c1b0d08
105 |
106 | audio/ogg; codec="vorbis"
107 |
108 | .sesx
109 | -EO
110 |
111 |
112 | 1097089397
113 | 1164201842
114 | /Users/jon/Documents/Adobe/Audition/13.0/propeller/propeller.sesx
115 |
116 | 2020-03-03
117 | 18:53:03
118 | 8643
119 | 1
120 |
121 |
122 |
123 | CuePoint Markers
124 | Cue
125 | f48000
126 |
127 |
128 | CD Track Markers
129 | Track
130 | f48000
131 |
132 |
133 | Subclip Markers
134 | InOut
135 | f48000
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/public/audio/propeller2.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/audio/propeller2.ogg
--------------------------------------------------------------------------------
/public/audio/propeller2.xmp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 | Adobe Audition 13.0 (Macintosh)
14 | 2020-03-03T18:35:51-05:00
15 | 2020-03-04T19:39:32-05:00
16 | 2020-03-04T19:39:32-05:00
17 | xmp.iid:a5e6fcc7-56df-4dbb-b2a8-57c35289e90e
18 | xmp.did:6ca1aa47-d2e4-4643-903b-2743896a366b
19 | xmp.did:3bcc9fb1-277e-4cc3-920d-a7ab9c1b0d08
20 |
21 |
22 |
23 | saved
24 | xmp.iid:3bcc9fb1-277e-4cc3-920d-a7ab9c1b0d08
25 | 2020-03-03T18:35:51-05:00
26 | Adobe Audition 13.0 (Macintosh)
27 | /metadata
28 |
29 |
30 | saved
31 | xmp.iid:5b8e1c11-5824-4c46-84f8-6f8cca039878
32 | 2020-03-03T22:08:18-05:00
33 | Adobe Audition 13.0 (Macintosh)
34 | /metadata
35 |
36 |
37 | converted
38 | from application/xml to audio/ogg; codec="vorbis"
39 |
40 |
41 | saved
42 | xmp.iid:fad28492-9517-4904-b6fb-2d46c6b46ff6
43 | 2020-03-03T22:08:18-05:00
44 | Adobe Audition 13.0 (Macintosh)
45 |
46 |
47 | converted
48 | from application/xml to audio/ogg; codec="vorbis"
49 |
50 |
51 | saved
52 | xmp.iid:6ca1aa47-d2e4-4643-903b-2743896a366b
53 | 2020-03-03T22:08:18-05:00
54 | Adobe Audition 13.0 (Macintosh)
55 | /
56 |
57 |
58 | saved
59 | xmp.iid:1e6294ff-0dfe-46c2-9405-7046f1a84ea4
60 | 2020-03-04T19:39:32-05:00
61 | Adobe Audition 13.0 (Macintosh)
62 | /metadata
63 |
64 |
65 | saved
66 | xmp.iid:a5e6fcc7-56df-4dbb-b2a8-57c35289e90e
67 | 2020-03-04T19:39:32-05:00
68 | Adobe Audition 13.0 (Macintosh)
69 | /
70 |
71 |
72 |
73 |
74 | xmp.iid:fad28492-9517-4904-b6fb-2d46c6b46ff6
75 | xmp.did:fad28492-9517-4904-b6fb-2d46c6b46ff6
76 | xmp.did:3bcc9fb1-277e-4cc3-920d-a7ab9c1b0d08
77 |
78 | audio/ogg; codec="vorbis"
79 | 2020-03-03
80 | 18:53:03
81 | 8642
82 |
83 | .sesx
84 | -EO
85 |
86 |
87 | 1097089397
88 | 1164201842
89 | /Users/jon/Documents/Adobe/Audition/13.0/propeller/propeller.sesx
90 |
91 |
92 |
93 |
94 | CuePoint Markers
95 | Cue
96 | f48000
97 |
98 |
99 | CD Track Markers
100 | Track
101 | f48000
102 |
103 |
104 | Subclip Markers
105 | InOut
106 | f48000
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/public/draco-gltf/draco_decoder.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/public/draco-gltf/draco_decoder.wasm
--------------------------------------------------------------------------------
/public/draco-gltf/draco_wasm_wrapper.js:
--------------------------------------------------------------------------------
1 | var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(d,k,f){d!=Array.prototype&&d!=Object.prototype&&(d[k]=f.value)};$jscomp.getGlobal=function(d){return"undefined"!=typeof window&&window===d?d:"undefined"!=typeof global&&null!=global?global:d};$jscomp.global=$jscomp.getGlobal(this);
2 | $jscomp.polyfill=function(d,k,f,u){if(k){f=$jscomp.global;d=d.split(".");for(u=0;u>>16&65535)*h+k*(f>>>16&65535)<<16>>>0)|0}},"es6","es3");
3 | $jscomp.polyfill("Math.clz32",function(d){return d?d:function(d){d=Number(d)>>>0;if(0===d)return 32;var f=0;0===(d&4294901760)&&(d<<=16,f+=16);0===(d&4278190080)&&(d<<=8,f+=8);0===(d&4026531840)&&(d<<=4,f+=4);0===(d&3221225472)&&(d<<=2,f+=2);0===(d&2147483648)&&f++;return f}},"es6","es3");$jscomp.polyfill("Math.trunc",function(d){return d?d:function(d){d=Number(d);if(isNaN(d)||Infinity===d||-Infinity===d||0===d)return d;var f=Math.floor(Math.abs(d));return 0>d?-f:f}},"es6","es3");
4 | $jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.Symbol=function(){var d=0;return function(k){return $jscomp.SYMBOL_PREFIX+(k||"")+d++}}();
5 | $jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var d=$jscomp.global.Symbol.iterator;d||(d=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[d]&&$jscomp.defineProperty(Array.prototype,d,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}};$jscomp.arrayIterator=function(d){var k=0;return $jscomp.iteratorPrototype(function(){return k>0];b|=e;if(0==e&&!c)break;d++;if(c&&d==c)break}c||(c=d);e="";if(128>b){for(;0e?b+=String.fromCharCode(e):(e-=65536,b+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else b+=String.fromCharCode(e)}}function ha(a,c){0<
16 | a%c&&(a+=c-a%c);return a}function r(){a.HEAP8=ia=new Int8Array(D);a.HEAP16=Ja=new Int16Array(D);a.HEAP32=E=new Int32Array(D);a.HEAPU8=W=new Uint8Array(D);a.HEAPU16=new Uint16Array(D);a.HEAPU32=new Uint32Array(D);a.HEAPF32=new Float32Array(D);a.HEAPF64=new Float64Array(D)}function B(e){for(;0>2]=e;e=la.buffer;for(var d=0;d>2],c.adjusted=e,(sa(p[d]),e)|0;e=E[e>>2];
18 | return(sa(b),e)|0}function Z(e,c){w.varargs=c;try{var b=w.get(),p=w.get(),d=w.get();e=0;Z.buffers||(Z.buffers=[null,[],[]],Z.printChar=function(c,b){var e=Z.buffers[c];f(e);0===b||10===b?((1===c?a.print:a.printErr)(h(e,0)),e.length=0):e.push(b)});for(c=0;c>2],k=E[p+(8*c+4)>>2],l=0;l=e&&(e=65536+((e&1023)<<10)|a.charCodeAt(++b)&1023);127>=e?++c:c=2047>=e?c+2:65535>=e?c+3:2097151>=e?c+4:67108863>=e?c+5:c+6}c=Array(c+1);b=0;e=c.length;if(0=f&&(f=65536+((f&1023)<<10)|a.charCodeAt(++d)&1023);if(127>=f){if(b>=e)break;c[b++]=f}else{if(2047>=f){if(b+1>=e)break;c[b++]=192|f>>6}else{if(65535>=f){if(b+2>=e)break;c[b++]=224|f>>12}else{if(2097151>=f){if(b+
22 | 3>=e)break;c[b++]=240|f>>18}else{if(67108863>=f){if(b+4>=e)break;c[b++]=248|f>>24}else{if(b+5>=e)break;c[b++]=252|f>>30;c[b++]=128|f>>24&63}c[b++]=128|f>>18&63}c[b++]=128|f>>12&63}c[b++]=128|f>>6&63}c[b++]=128|f&63}}c[b]=0}a=l.alloc(c,ia);l.copy(c,ia,a)}return a}function z(){throw"cannot construct a Status, no constructor in IDL";}function F(){this.ptr=Wa();t(F)[this.ptr]=this}function G(){this.ptr=Xa();t(G)[this.ptr]=this}function H(){this.ptr=Ya();t(H)[this.ptr]=this}function I(){this.ptr=Za();
23 | t(I)[this.ptr]=this}function J(){this.ptr=$a();t(J)[this.ptr]=this}function n(){this.ptr=ab();t(n)[this.ptr]=this}function P(){this.ptr=bb();t(P)[this.ptr]=this}function x(){this.ptr=cb();t(x)[this.ptr]=this}function K(){this.ptr=db();t(K)[this.ptr]=this}function q(){this.ptr=eb();t(q)[this.ptr]=this}function L(){this.ptr=fb();t(L)[this.ptr]=this}function M(){this.ptr=gb();t(M)[this.ptr]=this}function V(){this.ptr=hb();t(V)[this.ptr]=this}function Q(){this.ptr=ib();t(Q)[this.ptr]=this}function g(){this.ptr=
24 | jb();t(g)[this.ptr]=this}function C(){this.ptr=kb();t(C)[this.ptr]=this}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function N(){this.ptr=lb();t(N)[this.ptr]=this}function R(){this.ptr=mb();t(R)[this.ptr]=this}d=d||{};var a="undefined"!==typeof d?d:{},Qa=!1,Ra=!1;a.onRuntimeInitialized=function(){Qa=!0;if(Ra&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Ra=!0;if(Qa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=
25 | function(a){if("string"!==typeof a)return!1;a=a.split(".");return 2>a.length||3=a[1]?!0:0!=a[0]||10>2]},getStr:function(){return u(w.get())},get64:function(){var a=w.get(),c=w.get();0<=a?f(0===c):f(-1===c);return a},getZero:function(){f(0===w.get())}},va={},Ha=1;ka=function(a){f(!Sa);var c=ba;ba=ba+
40 | a+15&-16;return c}(4);Ca=ta=k(ba);ua=Ca+Fa;Da=k(ua);E[ka>>2]=Da;Sa=!0;a.wasmTableSize=468;a.wasmMaxTableSize=468;a.asmGlobalArg={};a.asmLibraryArg={abort:O,assert:f,enlargeMemory:function(){var e=a.usingWasm?65536:16777216,c=2147483648-e;if(E[ka>>2]>c)return!1;var b=A;for(A=Math.max(A,16777216);A>2];)A=536870912>=A?ha(2*A,e):Math.min(ha((3*A+2147483648)/4,e),c);e=a.reallocBuffer(A);if(!e||e.byteLength!=A)return A=b,!1;a.buffer=D=e;r();return!0},getTotalMemory:function(){return A},abortOnCannotGrowMemory:function(){O("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+
41 | A+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")},invoke_ii:function(e,c){try{return a.dynCall_ii(e,c)}catch(b){if("number"!==typeof b&&"longjmp"!==b)throw b;a.setThrew(1,0)}},invoke_iii:function(e,c,b){try{return a.dynCall_iii(e,c,b)}catch(p){if("number"!==typeof p&&"longjmp"!==p)throw p;a.setThrew(1,0)}},invoke_iiii:function(e,c,b,d){try{return a.dynCall_iiii(e,
42 | c,b,d)}catch(S){if("number"!==typeof S&&"longjmp"!==S)throw S;a.setThrew(1,0)}},invoke_iiiiiii:function(e,c,b,d,f,g,h){try{return a.dynCall_iiiiiii(e,c,b,d,f,g,h)}catch(da){if("number"!==typeof da&&"longjmp"!==da)throw da;a.setThrew(1,0)}},invoke_v:function(e){try{a.dynCall_v(e)}catch(c){if("number"!==typeof c&&"longjmp"!==c)throw c;a.setThrew(1,0)}},invoke_vi:function(e,c){try{a.dynCall_vi(e,c)}catch(b){if("number"!==typeof b&&"longjmp"!==b)throw b;a.setThrew(1,0)}},invoke_vii:function(e,c,b){try{a.dynCall_vii(e,
43 | c,b)}catch(p){if("number"!==typeof p&&"longjmp"!==p)throw p;a.setThrew(1,0)}},invoke_viii:function(e,c,b,d){try{a.dynCall_viii(e,c,b,d)}catch(S){if("number"!==typeof S&&"longjmp"!==S)throw S;a.setThrew(1,0)}},invoke_viiii:function(e,c,b,d,f){try{a.dynCall_viiii(e,c,b,d,f)}catch(xa){if("number"!==typeof xa&&"longjmp"!==xa)throw xa;a.setThrew(1,0)}},invoke_viiiii:function(e,c,b,d,f,g){try{a.dynCall_viiiii(e,c,b,d,f,g)}catch(ca){if("number"!==typeof ca&&"longjmp"!==ca)throw ca;a.setThrew(1,0)}},invoke_viiiiii:function(e,
44 | c,b,d,f,g,h){try{a.dynCall_viiiiii(e,c,b,d,f,g,h)}catch(da){if("number"!==typeof da&&"longjmp"!==da)throw da;a.setThrew(1,0)}},__ZSt18uncaught_exceptionv:v,___cxa_allocate_exception:function(a){return Ka(a)},___cxa_begin_catch:function(a){var c=y.infos[a];c&&!c.caught&&(c.caught=!0,v.uncaught_exception--);c&&(c.rethrown=!1);y.caught.push(a);y.addRef(y.deAdjust(a));return a},___cxa_find_matching_catch:la,___cxa_pure_virtual:function(){oa=!0;throw"Pure virtual function called!";},___cxa_throw:function(a,
45 | c,b){y.infos[a]={ptr:a,adjusted:a,type:c,destructor:b,refcount:0,caught:!1,rethrown:!1};y.last=a;"uncaught_exception"in v?v.uncaught_exception++:v.uncaught_exception=1;throw a+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";},___gxx_personality_v0:function(){},___resumeException:function(a){y.last||(y.last=a);throw a+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
46 | },___setErrNo:function(d){a.___errno_location&&(E[a.___errno_location()>>2]=d);return d},___syscall140:function(a,c){w.varargs=c;try{var b=w.getStreamFromFD();w.get();var d=w.get(),e=w.get(),f=w.get();FS.llseek(b,d,f);E[e>>2]=b.position;b.getdents&&0===d&&0===f&&(b.getdents=null);return 0}catch(ca){return"undefined"!==typeof FS&&ca instanceof FS.ErrnoError||O(ca),-ca.errno}},___syscall146:Z,___syscall6:function(a,c){w.varargs=c;try{var b=w.getStreamFromFD();FS.close(b);return 0}catch(p){return"undefined"!==
47 | typeof FS&&p instanceof FS.ErrnoError||O(p),-p.errno}},_abort:function(){a.abort()},_emscripten_memcpy_big:function(a,c,b){W.set(W.subarray(c,c+b),a);return a},_llvm_trap:function(){O("trap!")},_pthread_getspecific:function(a){return va[a]||0},_pthread_key_create:function(a,c){if(0==a)return 22;E[a>>2]=Ha;va[Ha]=0;Ha++;return 0},_pthread_once:ma,_pthread_setspecific:function(a,c){if(!(a in va))return 22;va[a]=c;return 0},flush_NO_FILESYSTEM:function(){var d=a._fflush;d&&d(0);if(d=Z.printChar){var c=
48 | Z.buffers;c[1].length&&d(1,10);c[2].length&&d(2,10)}},DYNAMICTOP_PTR:ka,tempDoublePtr:qb,ABORT:oa,STACKTOP:ta,STACK_MAX:ua};var Ua=a.asm(a.asmGlobalArg,a.asmLibraryArg,D);a.asm=Ua;a.___cxa_can_catch=function(){return a.asm.___cxa_can_catch.apply(null,arguments)};a.___cxa_is_pointer_type=function(){return a.asm.___cxa_is_pointer_type.apply(null,arguments)};var $a=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0.apply(null,
49 | arguments)},rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1.apply(null,arguments)},sb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform___destroy___0.apply(null,arguments)},tb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0.apply(null,
50 | arguments)},cb=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0.apply(null,arguments)},ub=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1.apply(null,arguments)},vb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform___destroy___0.apply(null,
51 | arguments)},wb=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_min_value_1.apply(null,arguments)},xb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0.apply(null,arguments)},yb=a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_range_0.apply(null,
52 | arguments)},bb=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return a.asm._emscripten_bind_AttributeTransformData_AttributeTransformData_0.apply(null,arguments)},zb=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return a.asm._emscripten_bind_AttributeTransformData___destroy___0.apply(null,arguments)},Ab=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return a.asm._emscripten_bind_AttributeTransformData_transform_type_0.apply(null,
53 | arguments)},ib=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=function(){return a.asm._emscripten_bind_DecoderBuffer_DecoderBuffer_0.apply(null,arguments)},Bb=a._emscripten_bind_DecoderBuffer_Init_2=function(){return a.asm._emscripten_bind_DecoderBuffer_Init_2.apply(null,arguments)},Cb=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return a.asm._emscripten_bind_DecoderBuffer___destroy___0.apply(null,arguments)},Db=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return a.asm._emscripten_bind_Decoder_DecodeBufferToMesh_2.apply(null,
54 | arguments)},Eb=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return a.asm._emscripten_bind_Decoder_DecodeBufferToPointCloud_2.apply(null,arguments)},jb=a._emscripten_bind_Decoder_Decoder_0=function(){return a.asm._emscripten_bind_Decoder_Decoder_0.apply(null,arguments)},Fb=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeByUniqueId_2.apply(null,arguments)},Gb=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=
55 | function(){return a.asm._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3.apply(null,arguments)},Hb=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeFloat_3.apply(null,arguments)},Ib=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3.apply(null,arguments)},Jb=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIdByName_2.apply(null,
56 | arguments)},Kb=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeId_2.apply(null,arguments)},Lb=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3.apply(null,arguments)},Mb=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3.apply(null,arguments)},Nb=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=
57 | function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3.apply(null,arguments)},Ob=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3.apply(null,arguments)},Pb=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeMetadata_2.apply(null,arguments)},Qb=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3.apply(null,
58 | arguments)},Rb=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3.apply(null,arguments)},Sb=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3.apply(null,arguments)},Tb=a._emscripten_bind_Decoder_GetAttribute_2=function(){return a.asm._emscripten_bind_Decoder_GetAttribute_2.apply(null,arguments)},Ub=a._emscripten_bind_Decoder_GetEncodedGeometryType_1=
59 | function(){return a.asm._emscripten_bind_Decoder_GetEncodedGeometryType_1.apply(null,arguments)},Vb=a._emscripten_bind_Decoder_GetFaceFromMesh_3=function(){return a.asm._emscripten_bind_Decoder_GetFaceFromMesh_3.apply(null,arguments)},Wb=a._emscripten_bind_Decoder_GetMetadata_1=function(){return a.asm._emscripten_bind_Decoder_GetMetadata_1.apply(null,arguments)},Xb=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return a.asm._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2.apply(null,
60 | arguments)},Yb=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return a.asm._emscripten_bind_Decoder_SkipAttributeTransform_1.apply(null,arguments)},Zb=a._emscripten_bind_Decoder___destroy___0=function(){return a.asm._emscripten_bind_Decoder___destroy___0.apply(null,arguments)},gb=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return a.asm._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0.apply(null,arguments)},$b=a._emscripten_bind_DracoFloat32Array_GetValue_1=
61 | function(){return a.asm._emscripten_bind_DracoFloat32Array_GetValue_1.apply(null,arguments)},ac=a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoFloat32Array___destroy___0.apply(null,arguments)},bc=a._emscripten_bind_DracoFloat32Array_size_0=function(){return a.asm._emscripten_bind_DracoFloat32Array_size_0.apply(null,arguments)},fb=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return a.asm._emscripten_bind_DracoInt16Array_DracoInt16Array_0.apply(null,
62 | arguments)},cc=a._emscripten_bind_DracoInt16Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt16Array_GetValue_1.apply(null,arguments)},dc=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt16Array___destroy___0.apply(null,arguments)},ec=a._emscripten_bind_DracoInt16Array_size_0=function(){return a.asm._emscripten_bind_DracoInt16Array_size_0.apply(null,arguments)},lb=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=function(){return a.asm._emscripten_bind_DracoInt32Array_DracoInt32Array_0.apply(null,
63 | arguments)},fc=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt32Array_GetValue_1.apply(null,arguments)},gc=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt32Array___destroy___0.apply(null,arguments)},hc=a._emscripten_bind_DracoInt32Array_size_0=function(){return a.asm._emscripten_bind_DracoInt32Array_size_0.apply(null,arguments)},db=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return a.asm._emscripten_bind_DracoInt8Array_DracoInt8Array_0.apply(null,
64 | arguments)},ic=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt8Array_GetValue_1.apply(null,arguments)},jc=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt8Array___destroy___0.apply(null,arguments)},kc=a._emscripten_bind_DracoInt8Array_size_0=function(){return a.asm._emscripten_bind_DracoInt8Array_size_0.apply(null,arguments)},Wa=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return a.asm._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0.apply(null,
65 | arguments)},lc=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoUInt16Array_GetValue_1.apply(null,arguments)},mc=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return a.asm._emscripten_bind_DracoUInt16Array___destroy___0.apply(null,arguments)},nc=a._emscripten_bind_DracoUInt16Array_size_0=function(){return a.asm._emscripten_bind_DracoUInt16Array_size_0.apply(null,arguments)},Za=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return a.asm._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0.apply(null,
66 | arguments)},oc=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoUInt32Array_GetValue_1.apply(null,arguments)},pc=a._emscripten_bind_DracoUInt32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoUInt32Array___destroy___0.apply(null,arguments)},qc=a._emscripten_bind_DracoUInt32Array_size_0=function(){return a.asm._emscripten_bind_DracoUInt32Array_size_0.apply(null,arguments)},Ya=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return a.asm._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0.apply(null,
67 | arguments)},rc=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoUInt8Array_GetValue_1.apply(null,arguments)},sc=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return a.asm._emscripten_bind_DracoUInt8Array___destroy___0.apply(null,arguments)},tc=a._emscripten_bind_DracoUInt8Array_size_0=function(){return a.asm._emscripten_bind_DracoUInt8Array_size_0.apply(null,arguments)},hb=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return a.asm._emscripten_bind_GeometryAttribute_GeometryAttribute_0.apply(null,
68 | arguments)},uc=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return a.asm._emscripten_bind_GeometryAttribute___destroy___0.apply(null,arguments)},kb=a._emscripten_bind_Mesh_Mesh_0=function(){return a.asm._emscripten_bind_Mesh_Mesh_0.apply(null,arguments)},vc=a._emscripten_bind_Mesh___destroy___0=function(){return a.asm._emscripten_bind_Mesh___destroy___0.apply(null,arguments)},wc=a._emscripten_bind_Mesh_num_attributes_0=function(){return a.asm._emscripten_bind_Mesh_num_attributes_0.apply(null,
69 | arguments)},xc=a._emscripten_bind_Mesh_num_faces_0=function(){return a.asm._emscripten_bind_Mesh_num_faces_0.apply(null,arguments)},yc=a._emscripten_bind_Mesh_num_points_0=function(){return a.asm._emscripten_bind_Mesh_num_points_0.apply(null,arguments)},zc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetDoubleEntry_2.apply(null,arguments)},Ac=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetEntryName_2.apply(null,
70 | arguments)},Bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetIntEntry_2.apply(null,arguments)},Cc=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetStringEntry_2.apply(null,arguments)},Dc=a._emscripten_bind_MetadataQuerier_HasDoubleEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasDoubleEntry_2.apply(null,arguments)},Ec=a._emscripten_bind_MetadataQuerier_HasEntry_2=
71 | function(){return a.asm._emscripten_bind_MetadataQuerier_HasEntry_2.apply(null,arguments)},Fc=a._emscripten_bind_MetadataQuerier_HasIntEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasIntEntry_2.apply(null,arguments)},Gc=a._emscripten_bind_MetadataQuerier_HasStringEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasStringEntry_2.apply(null,arguments)},eb=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return a.asm._emscripten_bind_MetadataQuerier_MetadataQuerier_0.apply(null,
72 | arguments)},Hc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return a.asm._emscripten_bind_MetadataQuerier_NumEntries_1.apply(null,arguments)},Ic=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return a.asm._emscripten_bind_MetadataQuerier___destroy___0.apply(null,arguments)},mb=a._emscripten_bind_Metadata_Metadata_0=function(){return a.asm._emscripten_bind_Metadata_Metadata_0.apply(null,arguments)},Jc=a._emscripten_bind_Metadata___destroy___0=function(){return a.asm._emscripten_bind_Metadata___destroy___0.apply(null,
73 | arguments)},Kc=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=function(){return a.asm._emscripten_bind_PointAttribute_GetAttributeTransformData_0.apply(null,arguments)},ab=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return a.asm._emscripten_bind_PointAttribute_PointAttribute_0.apply(null,arguments)},Lc=a._emscripten_bind_PointAttribute___destroy___0=function(){return a.asm._emscripten_bind_PointAttribute___destroy___0.apply(null,arguments)},Mc=a._emscripten_bind_PointAttribute_attribute_type_0=
74 | function(){return a.asm._emscripten_bind_PointAttribute_attribute_type_0.apply(null,arguments)},Nc=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return a.asm._emscripten_bind_PointAttribute_byte_offset_0.apply(null,arguments)},Oc=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return a.asm._emscripten_bind_PointAttribute_byte_stride_0.apply(null,arguments)},Pc=a._emscripten_bind_PointAttribute_data_type_0=function(){return a.asm._emscripten_bind_PointAttribute_data_type_0.apply(null,
75 | arguments)},Qc=a._emscripten_bind_PointAttribute_normalized_0=function(){return a.asm._emscripten_bind_PointAttribute_normalized_0.apply(null,arguments)},Rc=a._emscripten_bind_PointAttribute_num_components_0=function(){return a.asm._emscripten_bind_PointAttribute_num_components_0.apply(null,arguments)},Sc=a._emscripten_bind_PointAttribute_size_0=function(){return a.asm._emscripten_bind_PointAttribute_size_0.apply(null,arguments)},Tc=a._emscripten_bind_PointAttribute_unique_id_0=function(){return a.asm._emscripten_bind_PointAttribute_unique_id_0.apply(null,
76 | arguments)},Xa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return a.asm._emscripten_bind_PointCloud_PointCloud_0.apply(null,arguments)},Uc=a._emscripten_bind_PointCloud___destroy___0=function(){return a.asm._emscripten_bind_PointCloud___destroy___0.apply(null,arguments)},Vc=a._emscripten_bind_PointCloud_num_attributes_0=function(){return a.asm._emscripten_bind_PointCloud_num_attributes_0.apply(null,arguments)},Wc=a._emscripten_bind_PointCloud_num_points_0=function(){return a.asm._emscripten_bind_PointCloud_num_points_0.apply(null,
77 | arguments)},Xc=a._emscripten_bind_Status___destroy___0=function(){return a.asm._emscripten_bind_Status___destroy___0.apply(null,arguments)},Yc=a._emscripten_bind_Status_code_0=function(){return a.asm._emscripten_bind_Status_code_0.apply(null,arguments)},Zc=a._emscripten_bind_Status_error_msg_0=function(){return a.asm._emscripten_bind_Status_error_msg_0.apply(null,arguments)},$c=a._emscripten_bind_Status_ok_0=function(){return a.asm._emscripten_bind_Status_ok_0.apply(null,arguments)},ad=a._emscripten_bind_VoidPtr___destroy___0=
78 | function(){return a.asm._emscripten_bind_VoidPtr___destroy___0.apply(null,arguments)},bd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM.apply(null,arguments)},cd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM.apply(null,arguments)},dd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=
79 | function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM.apply(null,arguments)},ed=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM.apply(null,arguments)},fd=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE.apply(null,
80 | arguments)},gd=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD.apply(null,arguments)},hd=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH.apply(null,arguments)},id=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_COLOR.apply(null,arguments)},jd=
81 | a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_GENERIC.apply(null,arguments)},kd=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_INVALID.apply(null,arguments)},ld=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_NORMAL.apply(null,arguments)},md=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=
82 | function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_POSITION.apply(null,arguments)},nd=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD.apply(null,arguments)},od=a._emscripten_enum_draco_StatusCode_ERROR=function(){return a.asm._emscripten_enum_draco_StatusCode_ERROR.apply(null,arguments)},pd=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=function(){return a.asm._emscripten_enum_draco_StatusCode_INVALID_PARAMETER.apply(null,
83 | arguments)},qd=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return a.asm._emscripten_enum_draco_StatusCode_IO_ERROR.apply(null,arguments)},rd=a._emscripten_enum_draco_StatusCode_OK=function(){return a.asm._emscripten_enum_draco_StatusCode_OK.apply(null,arguments)},sd=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return a.asm._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION.apply(null,arguments)},td=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return a.asm._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION.apply(null,
84 | arguments)},nb=a._emscripten_replace_memory=function(){return a.asm._emscripten_replace_memory.apply(null,arguments)};a._free=function(){return a.asm._free.apply(null,arguments)};a._llvm_bswap_i32=function(){return a.asm._llvm_bswap_i32.apply(null,arguments)};var Ka=a._malloc=function(){return a.asm._malloc.apply(null,arguments)};a._memcpy=function(){return a.asm._memcpy.apply(null,arguments)};a._memmove=function(){return a.asm._memmove.apply(null,arguments)};a._memset=function(){return a.asm._memset.apply(null,
85 | arguments)};a._sbrk=function(){return a.asm._sbrk.apply(null,arguments)};a.establishStackSpace=function(){return a.asm.establishStackSpace.apply(null,arguments)};a.getTempRet0=function(){return a.asm.getTempRet0.apply(null,arguments)};a.runPostSets=function(){return a.asm.runPostSets.apply(null,arguments)};var sa=a.setTempRet0=function(){return a.asm.setTempRet0.apply(null,arguments)};a.setThrew=function(){return a.asm.setThrew.apply(null,arguments)};a.stackAlloc=function(){return a.asm.stackAlloc.apply(null,
86 | arguments)};a.stackRestore=function(){return a.asm.stackRestore.apply(null,arguments)};a.stackSave=function(){return a.asm.stackSave.apply(null,arguments)};a.dynCall_ii=function(){return a.asm.dynCall_ii.apply(null,arguments)};a.dynCall_iii=function(){return a.asm.dynCall_iii.apply(null,arguments)};a.dynCall_iiii=function(){return a.asm.dynCall_iiii.apply(null,arguments)};a.dynCall_iiiiiii=function(){return a.asm.dynCall_iiiiiii.apply(null,arguments)};a.dynCall_v=function(){return a.asm.dynCall_v.apply(null,
87 | arguments)};a.dynCall_vi=function(){return a.asm.dynCall_vi.apply(null,arguments)};a.dynCall_vii=function(){return a.asm.dynCall_vii.apply(null,arguments)};a.dynCall_viii=function(){return a.asm.dynCall_viii.apply(null,arguments)};a.dynCall_viiii=function(){return a.asm.dynCall_viiii.apply(null,arguments)};a.dynCall_viiiii=function(){return a.asm.dynCall_viiiii.apply(null,arguments)};a.dynCall_viiiiii=function(){return a.asm.dynCall_viiiiii.apply(null,arguments)};a.asm=Ua;a.then=function(d){if(a.calledRun)d(a);
88 | else{var c=a.onRuntimeInitialized;a.onRuntimeInitialized=function(){c&&c();d(a)}}return a};na.prototype=Error();na.prototype.constructor=na;ra=function c(){a.calledRun||wa();a.calledRun||(ra=c)};a.run=wa;a.exit=function(c,b){if(!b||!a.noExitRuntime||0!==c){if(!a.noExitRuntime&&(oa=!0,ta=void 0,B(ob),a.onExit))a.onExit(c);qa&&process.exit(c);a.quit(c,new na(c))}};a.abort=O;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0=l.size?(f(0>=
91 | 1;break;case 4:d>>=2;break;case 8:d>>=3}for(var c=0;c
2 |
3 |
4 |
5 |
6 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
30 |
31 |
32 |
41 | Good, Fast, Cheap -- pick any two.
42 |
43 |
44 |
45 |
46 |
47 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | #### An experiment combining React and 3D stuffs:
4 |
5 | http://jonarnold.dev/good-fast-cheap/
6 |
7 |
13 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'three'
2 | import React, { Suspense, useState, useRef, useEffect } from 'react'
3 | import { Canvas, useLoader, useThree } from 'react-three-fiber'
4 | import Controls from './components/Controls'
5 | import Environment from './components/Environment'
6 | import GFCMachine from './components/GFCMachine'
7 | import Effects from './components/Effects'
8 | import './styles.css'
9 | import UI from './components/UI';
10 | import UISecondary from './components/UISecondary';
11 | import Loading from './components/Loading';
12 |
13 | export default function App() {
14 | // Controls disable pointerevents on movement to save some CPU cost
15 | // const [active, set] = useState(false);
16 | const [allowSound, setAllowSound] = useState(false);
17 | const [selections, setSelections] = React.useState([])
18 | const [modelLoaded, setModelLoaded] = React.useState(false);
19 | const [loadUI, setLoadUI] = React.useState(false);
20 |
21 | React.useEffect(() => {
22 | if(modelLoaded){
23 | setTimeout(() => {
24 | setLoadUI(true)
25 | }, 2000)
26 | }
27 | }, [modelLoaded])
28 |
29 | const toggleSound = () => {
30 | setAllowSound(s => !s);
31 | }
32 |
33 | const setNewSelection = (id) => {
34 | //only update if this is a new value
35 | if(selections.includes(id)){
36 | return;
37 | }
38 |
39 | let updatedSelections = selections;
40 |
41 | if (selections.length === 2){
42 | //keep last selection, make it first
43 | updatedSelections = selections.slice(1, 2);
44 | }
45 |
46 | //add new last selection
47 | setSelections(updatedSelections.concat([id]));
48 |
49 | }
50 |
51 | return (
52 |
53 | {!loadUI &&
}
54 | {loadUI && }
55 |
56 |
57 |
58 |
89 |
90 |
91 | {loadUI && }
92 |
93 | )
94 | }
95 |
96 |
97 | const PropellerSound = ({ url }) => {
98 | const sound = useRef()
99 | const { camera } = useThree()
100 | const [listener] = useState(() => new THREE.AudioListener())
101 | const buffer = useLoader(THREE.AudioLoader, url);
102 | useEffect(() => {
103 | sound.current.setBuffer(buffer)
104 | sound.current.setRefDistance(1)
105 | sound.current.setLoop(true)
106 | sound.current.play()
107 | camera.add(listener)
108 | return () => {
109 | if(sound.current.isPlaying) {
110 | sound.current.stop()
111 | }
112 | camera.remove(listener);
113 | }
114 | }, [])
115 | return
116 | }
--------------------------------------------------------------------------------
/src/audio/button-click.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/button-click.mp3
--------------------------------------------------------------------------------
/src/audio/button-inactive.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/button-inactive.mp3
--------------------------------------------------------------------------------
/src/audio/propeller.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/propeller.ogg
--------------------------------------------------------------------------------
/src/audio/propeller.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/propeller.wav
--------------------------------------------------------------------------------
/src/audio/propeller.xmp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 | Adobe Audition 13.0 (Macintosh)
14 | 2020-03-03T18:35:51-05:00
15 | 2020-03-03T19:25:21-05:00
16 | 2020-03-03T19:25:21-05:00
17 | xmp.iid:02c7c0ed-be59-47cb-bae5-6e8c9d73cb1b
18 | xmp.did:02c7c0ed-be59-47cb-bae5-6e8c9d73cb1b
19 | xmp.did:3bcc9fb1-277e-4cc3-920d-a7ab9c1b0d08
20 |
21 |
22 |
23 | saved
24 | xmp.iid:3bcc9fb1-277e-4cc3-920d-a7ab9c1b0d08
25 | 2020-03-03T18:35:51-05:00
26 | Adobe Audition 13.0 (Macintosh)
27 | /metadata
28 |
29 |
30 | saved
31 | xmp.iid:47035394-b54a-4b0a-a5ae-17a4304ed93a
32 | 2020-03-03T19:25:21-05:00
33 | Adobe Audition 13.0 (Macintosh)
34 | /metadata
35 |
36 |
37 | converted
38 | from application/xml to audio/ogg; codec="vorbis"
39 |
40 |
41 | saved
42 | xmp.iid:c02310a5-2d6e-468d-acff-10746e4bae0a
43 | 2020-03-03T19:25:21-05:00
44 | Adobe Audition 13.0 (Macintosh)
45 |
46 |
47 | converted
48 | from application/xml to audio/ogg; codec="vorbis"
49 |
50 |
51 | saved
52 | xmp.iid:02c7c0ed-be59-47cb-bae5-6e8c9d73cb1b
53 | 2020-03-03T19:25:21-05:00
54 | Adobe Audition 13.0 (Macintosh)
55 | /
56 |
57 |
58 |
59 |
60 | xmp.iid:c02310a5-2d6e-468d-acff-10746e4bae0a
61 | xmp.did:c02310a5-2d6e-468d-acff-10746e4bae0a
62 | xmp.did:3bcc9fb1-277e-4cc3-920d-a7ab9c1b0d08
63 |
64 | audio/ogg; codec="vorbis"
65 | 2020-03-03
66 | 18:53:03
67 | 3509
68 |
69 | .sesx
70 | -EO
71 |
72 |
73 | 1097089397
74 | 1164201842
75 | /Users/jon/Documents/Adobe/Audition/13.0/propeller/propeller.sesx
76 |
77 |
78 |
79 |
80 | CuePoint Markers
81 | Cue
82 | f48000
83 |
84 |
85 | CD Track Markers
86 | Track
87 | f48000
88 |
89 |
90 | Subclip Markers
91 | InOut
92 | f48000
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/src/audio/servo1.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/servo1.mp3
--------------------------------------------------------------------------------
/src/audio/servo2.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/servo2.mp3
--------------------------------------------------------------------------------
/src/audio/servo3.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/servo3.mp3
--------------------------------------------------------------------------------
/src/audio/squeak1.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/squeak1.mp3
--------------------------------------------------------------------------------
/src/audio/squeak2.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/squeak2.mp3
--------------------------------------------------------------------------------
/src/audio/squeak3.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/audio/squeak3.mp3
--------------------------------------------------------------------------------
/src/components/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Modal from '@material-ui/core/Modal';
3 | import Backdrop from '@material-ui/core/Backdrop';
4 | import Fade from '@material-ui/core/Fade';
5 | import { makeStyles } from '@material-ui/core/styles';
6 | import jonImg from '../images/jon.jpg';
7 | import './About.scss';
8 |
9 | export default ({modalOpen, setModalOpen}) => {
10 | const classes = useStyles();
11 | return (
12 | setModalOpen(false)}
18 | closeAfterTransition
19 | BackdropComponent={Backdrop}
20 | BackdropProps={{
21 | timeout: 500,
22 | classes: {
23 | root: classes.background
24 | }
25 | }}
26 | >
27 |
28 |
29 |
30 |

31 |
An experiment in...
32 |
40 |
41 |
42 |
43 | )
44 | }
45 |
46 | const useStyles = makeStyles(theme => ({
47 | modal: {
48 | display: 'flex',
49 | alignItems: 'center',
50 | justifyContent: 'center',
51 | },
52 | background: {
53 | backgroundColor: 'rgba(255, 255, 255, .6)',
54 | backdropFilter: 'blur(5px)'
55 | },
56 | }));
--------------------------------------------------------------------------------
/src/components/About.scss:
--------------------------------------------------------------------------------
1 | .About {
2 | display: grid;
3 | grid-template-columns: auto 1fr;
4 | grid-template-rows: 6.4rem 1fr;
5 | outline: none;
6 | position: relative;
7 | background-color: #FFF;
8 | max-width: 70rem;
9 | margin: 4rem;
10 | padding: 2.4rem;
11 | box-shadow: 0 20px 40px rgba(0, 0, 0, .05);
12 |
13 | color: #4E4E4E;
14 | z-index: 9999;
15 |
16 | animation: open .3s;
17 | animation-fill-mode: backwards;
18 |
19 | &__icon {
20 | grid-column: 1 / 2;
21 | grid-row: 1 / -1;
22 | width: 6.4rem;
23 | height: 6.4rem;
24 | animation-delay: .5s !important;
25 | border: 2px solid #fff;
26 | box-shadow: 0 2px 4px rgba(0, 0, 0, .15);
27 | border-radius: 200px;
28 | }
29 |
30 | &__title {
31 | color: #5f656b;
32 | font-size: 3rem;
33 | display: block;
34 | margin: 0;
35 | padding: 0;
36 | padding-top: 1.5rem;
37 | padding-left: 2.4rem;
38 | padding-right: 2.4rem;
39 | font-weight: 300;
40 | animation-delay: .75s !important;
41 | }
42 |
43 | &__body {
44 | margin: 0;
45 | padding: 0;
46 | margin-top: 1.8rem;
47 | font-weight: 500;
48 | font-size: 1.8rem;
49 | line-height: 2.5rem;
50 | animation-delay: 1s !important;
51 | & ul {
52 | margin: 0;
53 | padding: 0;
54 | padding-left: 4.5rem;
55 | padding-right: 4.5rem;
56 |
57 | & li {
58 | margin-bottom: 2.4rem;
59 |
60 | & a {
61 | color: #1B51B9;
62 | text-decoration: none;
63 | transition: 200ms;
64 | border-bottom: solid 2px transparent;
65 |
66 | &:hover {
67 | border-bottom: solid 2px #367BFF;
68 | }
69 | }
70 | }
71 | }
72 | }
73 |
74 | &__animation {
75 | animation: fadeIn 1.5s;
76 | animation-fill-mode: backwards;
77 | }
78 | }
79 |
80 | .About .close {
81 | position: absolute;
82 | top: 1rem;
83 | right: 1rem;
84 | border: none;
85 | background: none;
86 | outline: none;
87 | width: 5rem;
88 | height: 5rem;
89 | font-size: 3rem;
90 | line-height: 0rem;
91 | display: block;
92 | cursor: pointer;
93 | font-family: sans-serif;
94 | color: #93989e;
95 | transition: 200ms;
96 | }
97 |
98 | .About .close:hover {
99 | color: #5f656b;
100 | }
101 |
102 |
103 | @media screen and (max-width: 535px) {
104 | .About {
105 | grid-template-columns: 1fr;
106 | grid-template-rows: 6.4rem 4.8rem 1fr;
107 | margin: 2rem;
108 | padding: 2rem;
109 |
110 | &__icon {
111 | grid-column: 1 / 2;
112 | grid-row: 1 / 2;
113 | width: 6.4rem;
114 | height: 6.4rem;
115 | }
116 |
117 | &__title {
118 | color: #5f656b;
119 | font-size: 3rem;
120 | display: block;
121 | margin: 0;
122 | padding: 0;
123 | margin-top: 2rem;
124 | }
125 |
126 | &__body {
127 | margin: 0;
128 | padding: 0;
129 | margin-top: 3rem;
130 | font-weight: 500;
131 | font-size: 1.8rem;
132 | line-height: 2.5rem;
133 | animation-delay: 1s !important;
134 | & ul {
135 | margin: 0;
136 | padding: 0;
137 | padding-left: 2rem;
138 |
139 | & li {
140 | margin-bottom: 2rem;
141 |
142 | & a {
143 | color: #1B51B9;
144 | text-decoration: none;
145 | transition: 200ms;
146 | border-bottom: solid 2px transparent;
147 |
148 | &:hover {
149 | border-bottom: solid 2px #367BFF;
150 | }
151 | }
152 | }
153 | }
154 | }
155 | }
156 | }
157 |
158 |
159 |
160 |
161 |
162 |
163 | @keyframes fadeIn {
164 | from {
165 | transform: translateY(-7px);
166 | opacity: 0;
167 | }
168 | to {
169 | transform: translateY(0px);
170 | opacity: 1;
171 | }
172 | }
173 |
174 | @keyframes open {
175 | from {
176 | transform: scale(.9);
177 | opacity: 0;
178 | }
179 | to {
180 | transform: scale(1);
181 | opacity: 1;
182 | }
183 | }
184 |
185 | @keyframes close {
186 | from {
187 | transform: scale(1);
188 | opacity: 0;
189 | }
190 | to {
191 | transform: scale(.9);
192 | opacity: 1;
193 | }
194 | }
195 |
196 | // @media screen and (max-width: 430px) {
197 | // .About__icon {
198 | // width: 10rem;
199 | // height: 10rem;
200 | // }
201 |
202 | // .About__body {
203 | // line-height: 2.5rem;
204 | // }
205 | // }
206 |
207 | @media screen and (max-width: 370px) {
208 | .About {
209 | grid-template-rows: 4.8rem 4.8rem 1fr;
210 | margin: 1.5rem;
211 | padding: 1.5rem;
212 | }
213 |
214 | .About__icon {
215 | width: 4.8rem;
216 | height: 4.8rem;
217 | }
218 |
219 | .About__title {
220 | font-size: 2.5rem;
221 | }
222 |
223 | .About__body {
224 | font-size: 1.6rem;
225 | line-height: 2rem;
226 | }
227 | }
--------------------------------------------------------------------------------
/src/components/Controls.js:
--------------------------------------------------------------------------------
1 | import React, { useRef, useEffect } from 'react'
2 | import { extend, useThree, useFrame } from 'react-three-fiber'
3 | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
4 |
5 | extend({ OrbitControls })
6 |
7 | export default function Controls({ disable, ...props }) {
8 | const { camera, gl } = useThree()
9 | const ref = useRef()
10 | useFrame(() => ref.current.update())
11 |
12 | useEffect(() => {
13 | if (disable) {
14 | ref.current.addEventListener('start', () => disable(true))
15 | ref.current.addEventListener('end', () => disable(false))
16 | }
17 | }, [])
18 |
19 | return (
20 |
35 | )
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/Effects.js:
--------------------------------------------------------------------------------
1 | import { useMemo, useEffect } from 'react'
2 | import { useThree, useFrame, useLoader } from 'react-three-fiber'
3 | import {
4 | SMAAImageLoader,
5 | BlendFunction,
6 | KernelSize,
7 | BloomEffect,
8 | EffectComposer,
9 | EffectPass,
10 | RenderPass,
11 | SMAAEffect,
12 | GammaCorrectionEffect
13 | } from 'postprocessing'
14 |
15 | // Fix smaa loader signature
16 | // Will not be neccessary next version: https://github.com/vanruesc/postprocessing/commit/f05bb85fc9548458ee5e4a24026f308f0a8b72d4
17 | const _load = SMAAImageLoader.prototype.load
18 | SMAAImageLoader.prototype.load = function(_, set) {
19 | return _load.bind(this)(set)
20 | }
21 |
22 | export default function Effects() {
23 | const { gl, scene, camera, size } = useThree()
24 | const smaa = useLoader(SMAAImageLoader)
25 | const composer = useMemo(() => {
26 | const composer = new EffectComposer(gl)
27 | composer.addPass(new RenderPass(scene, camera))
28 | const smaaEffect = new SMAAEffect(...smaa);
29 | smaaEffect.colorEdgesMaterial.setEdgeDetectionThreshold(0.1)
30 | const gammaCorrection = new GammaCorrectionEffect()
31 | const bloom = new BloomEffect({
32 | blendFunction: BlendFunction.ADD,
33 | kernelSize: KernelSize.HUGE,
34 | luminanceThreshold: 0.6,
35 | height: 750
36 | })
37 | bloom.blendMode.opacity.value = 2
38 | //const effectPass = new EffectPass(camera, gammaCorrection, smaaEffect, bloom)
39 | const effectPass = new EffectPass(camera, gammaCorrection, smaaEffect, bloom)
40 | effectPass.renderToScreen = true
41 | composer.addPass(effectPass)
42 | return composer
43 | }, [])
44 | useEffect(() => void composer.setSize(size.width, size.height), [size])
45 | return useFrame((_, delta) => composer.render(delta), 1)
46 | }
47 |
--------------------------------------------------------------------------------
/src/components/Environment.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'three'
2 | import { useEffect } from 'react'
3 | import { useThree, useLoader } from 'react-three-fiber'
4 | import { HDRCubeTextureLoader } from 'three/examples/jsm/loaders/HDRCubeTextureLoader'
5 |
6 | export default function Environment({ background = false }) {
7 | const { gl, scene } = useThree()
8 | const [cubeMap] = useLoader(HDRCubeTextureLoader, [['px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr']], loader => {
9 | loader.setDataType(THREE.UnsignedByteType)
10 | loader.setPath('HDR/')
11 | })
12 | useEffect(() => {
13 | const gen = new THREE.PMREMGenerator(gl)
14 | gen.compileEquirectangularShader()
15 | const hdrCubeRenderTarget = gen.fromCubemap(cubeMap)
16 | cubeMap.dispose()
17 | gen.dispose()
18 | // if (background) scene.background = hdrCubeRenderTarget.texture
19 | scene.environment = hdrCubeRenderTarget.texture
20 | // scene.background.convertSRGBToLinear()
21 | return () => (scene.environment = null)
22 | }, [cubeMap])
23 | return null
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/GFCMachine.js:
--------------------------------------------------------------------------------
1 | /*
2 | auto-generated by: https://github.com/react-spring/gltfjsx
3 | */
4 |
5 | import * as THREE from 'three'
6 | import React, { useRef, useState, useEffect } from 'react'
7 | import { useLoader, useFrame } from 'react-three-fiber'
8 | import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
9 | import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
10 | import { useSpring, animated as a } from 'react-spring/three'
11 | import propellerImg from '../images/propeller.png'
12 |
13 | import buttonAudio from '../audio/button-click.mp3';
14 | import buttonInactiveAudio from '../audio/button-inactive.mp3';
15 | import servo1Audio from '../audio/servo1.mp3';
16 | import servo2Audio from '../audio/servo2.mp3';
17 | import servo3Audio from '../audio/servo3.mp3';
18 |
19 | const buttonSound = new Audio(buttonAudio);
20 | const buttonInactiveSound = new Audio(buttonInactiveAudio);
21 | const servo1Sound = new Audio(servo1Audio);
22 | const servo2Sound = new Audio(servo2Audio);
23 | const servo3Sound = new Audio(servo3Audio);
24 |
25 | function playAudio(audio, volume = 1, loop = false) {
26 | audio.currentTime = 0
27 | audio.volume = volume
28 | audio.loop = loop
29 | audio.play()
30 | }
31 |
32 | function playRandomServo() {
33 | const vol = .75;
34 | const rand = Math.floor(Math.random() * 3) + 1;
35 |
36 | switch(rand) {
37 | case 1:
38 | playAudio(servo1Sound, vol, false);
39 | return;
40 | case 2:
41 | playAudio(servo2Sound, vol, false);
42 | return;
43 | default:
44 | playAudio(servo3Sound, vol, false);
45 | }
46 | }
47 |
48 | export default function GFCMachine({selections, allowSound, setModelLoaded, setNewSelection}) {
49 | const group = useRef();
50 | const outerGroup = useRef();
51 | const { nodes, materials } = useLoader(GLTFLoader, 'gfc-hq.glb', loader => {
52 | const dracoLoader = new DRACOLoader()
53 | dracoLoader.setDecoderPath('draco-gltf/')
54 | loader.setDRACOLoader(dracoLoader)
55 | })
56 |
57 | const [hovered, setHover] = useState(false);
58 | useEffect(() => void (document.body.style.cursor = hovered ? 'pointer' : 'auto'), [hovered]);
59 |
60 | //Start CSS
61 | React.useEffect(() => {
62 | setModelLoaded(true);
63 | }, []);
64 |
65 | const [propellerTex] = useLoader(THREE.TextureLoader, [propellerImg])
66 |
67 | const propeller = useRef();
68 | const sphere = useRef(); //only for init spinning
69 | useFrame( ({ clock }) => {
70 | propeller.current.rotation.y += .4;
71 |
72 | if(sphere.current !== null && selections.length < 2) {
73 | sphere.current.rotation.y += .04;
74 | }
75 |
76 | outerGroup.current.position.y = Math.sin(clock.getElapsedTime() * 1.1) * .057 + 0.1;
77 | outerGroup.current.position.x = Math.sin(clock.getElapsedTime() * 1.5) * .05;
78 | outerGroup.current.position.z = Math.sin(clock.getElapsedTime() * 1.3) * .05;
79 | outerGroup.current.rotation.y = -Math.sin(clock.getElapsedTime() * .25) * .25 - 1.60; //speed, amount, rotation tweak
80 | }
81 | )
82 |
83 | const handleClick = (id) => {
84 | if(!isActive(id)){
85 | if(allowSound){
86 | playRandomServo();
87 | playAudio(buttonSound, 1, false);
88 | }
89 | setNewSelection(id);
90 | } else {
91 | if(allowSound){
92 | playAudio(buttonInactiveSound, 1, false);
93 | }
94 | }
95 | }
96 |
97 | const isActive = (selection) => {
98 | return selections.includes(selection)
99 | }
100 |
101 | const [initLights, setInitLights] = useState(['good', 'fast', 'cheap']);
102 | const [initLightsIdx, setInitLightsIdx] = useState(0);
103 |
104 | useEffect(() => {
105 | let interval;
106 | window.clearInterval(interval);
107 | if(selections.length === 2) {
108 | window.clearInterval(interval);
109 | setInitLights([]);
110 | } else {
111 | const filteredInitLights = initLights.filter(i => i !== selections[0])
112 | interval = window.setInterval(() => {
113 | setInitLightsIdx(idx => (idx + 1) % filteredInitLights.length);
114 | }, 700)
115 | setInitLights(filteredInitLights);
116 | }
117 |
118 | return () => window.clearInterval(interval);
119 | }, [selections])
120 |
121 |
122 | const isInitActive = (selection) => {
123 | return selection === initLights[initLightsIdx]
124 | }
125 |
126 |
127 | const sphereRotVal = () => {
128 | //HACK I don't know why I have to do this but putting this default spin
129 | //masks the fact that the init constant spin doesn't seemlessly animate
130 | //into the Spring animation when the first 2 selections are made.
131 | //Whithout this, the first 2 selections just pops to some selections.
132 | //See never/always comments below
133 | if (selections.length < 2) {
134 | return 5;
135 | }
136 |
137 | if(selections.every(s => s !== 'good')) { //never animates on first selection (wtf?)
138 | return Math.PI/1.5;
139 | } else if(selections.every(s => s !== 'fast')) {
140 | return 0;
141 | } else if(selections.every(s => s !== 'cheap')) { //always animates on first selection (wtf?)
142 | return -Math.PI/1.5;
143 | }
144 | }
145 |
146 |
147 | const {buttonPos1, buttonPos2, buttonPos3} = useSpring({
148 | buttonPos1: isActive('good') ? -.06 : .06,
149 | buttonPos2: isActive('fast') ? -.06 : .06,
150 | buttonPos3: isActive('cheap') ? -.06 : .06,
151 | config: { duration: 150 }
152 | })
153 |
154 | const {arrowRot1, arrowRot2, arrowRot3} = useSpring({
155 | arrowRot1: isActive('good') ? Math.PI : 0,
156 | arrowRot2: isActive('fast') ? Math.PI : 0,
157 | arrowRot3: isActive('cheap') ? Math.PI : 0,
158 | config: { mass: 1, tension: 150, friction: 12 }
159 | })
160 |
161 | const {sphereRot} = useSpring({
162 | to: {sphereRot: sphereRotVal()},
163 | from: {sphereRot: 16}
164 | })
165 |
166 | const {machineY} = useSpring({
167 | to: {machineY: 0},
168 | from: {machineY: 3.2},
169 | delay: 500,
170 | config: { mass: 1, tension: 280, friction: 120 }
171 | })
172 |
173 | return (
174 |
178 | [0, y, 0])}
182 | >
183 |
184 |
185 |
186 | {/* ARROWS */}
187 | [r, 0, 0])}
192 | />
193 | [r, 0, 0])}
198 | />
199 | [r, 0, 0])}
204 | />
205 |
206 |
207 | {/* BUTTONS */}
208 | [p, 0.33, 0.83])}
212 | onPointerOver={() => setHover(true)}
213 | onPointerOut={() => setHover(false)}
214 | onPointerDown={() => handleClick('good')}
215 | />
216 | [p, 0.33, -0.82])}
220 | onPointerOver={() => setHover(true)}
221 | onPointerOut={() => setHover(false)}
222 | onPointerDown={() => handleClick('fast')}
223 | />
224 | [p, -1.09, 0])}
228 | onPointerOver={() => setHover(true)}
229 | onPointerOut={() => setHover(false)}
230 | onPointerDown={() => handleClick('cheap')}
231 | />
232 |
233 |
234 | {/* LIGHTS */}
235 |
236 |
242 |
243 |
244 |
250 |
251 |
252 |
258 |
259 |
260 |
261 | {/* SPHERE */}
262 | {selections.length === 2
263 | ?
264 | [0, r, 0])}
269 | />
270 | :
271 |
276 | }
277 |
278 |
279 | {/* PROPELLER */}
280 |
281 |
282 |
283 |
289 |
290 |
291 |
292 |
293 |
294 | )
295 | }
296 |
--------------------------------------------------------------------------------
/src/components/Loading.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useSpring, animated } from 'react-spring';
3 | import './Loading.scss';
4 |
5 | export default (props) => {
6 |
7 | const tween = useSpring({opacity: props.modelLoaded ? 0 : 1})
8 | return (
9 |
10 |
11 |
12 |
13 |
14 | Loading
15 |
16 |
17 | )
18 | }
--------------------------------------------------------------------------------
/src/components/Loading.scss:
--------------------------------------------------------------------------------
1 | .Loading {
2 | position: absolute;
3 | top: 45%;
4 | left: 50%;
5 | transform: translate(-50%, -50%);
6 | width: 20rem;
7 | height: 20rem;
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 |
12 | &__text {
13 | position: absolute;
14 | font-size: 2rem;
15 | text-transform: uppercase;
16 | letter-spacing: .2rem;
17 | }
18 |
19 | &__spinner {
20 | position: absolute;
21 | width: 100%;
22 | height: 100%;
23 | border: solid 5px rgba(255, 255, 255, .2);
24 | border-right: solid 5px white;
25 | border-radius: 100%;
26 | animation: rotation 1s infinite linear;
27 | }
28 |
29 |
30 | }
31 |
32 | @keyframes rotation {
33 | from {
34 | -webkit-transform: rotate(0deg);
35 | }
36 | to {
37 | -webkit-transform: rotate(359deg);
38 | }
39 | }
--------------------------------------------------------------------------------
/src/components/SoundButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './SoundButton.scss';
3 |
4 | export default ({toggleSound, allowSound}) => {
5 | return (
6 |
14 | )
15 | }
--------------------------------------------------------------------------------
/src/components/SoundButton.scss:
--------------------------------------------------------------------------------
1 |
2 | .SoundButton {
3 | margin:0;
4 | padding: 0;
5 | position: absolute;
6 | left: 2rem;
7 | bottom: 3rem;
8 | display: block;
9 | outline: none; //may god have mercy on my soul
10 | width: 10rem;
11 | height: 4.4rem;
12 | cursor: pointer;
13 | border: none;
14 | background: none;
15 | display: flex;
16 | align-items: center;
17 | color: var(--default-color);
18 | transition: var(--transition-time);
19 |
20 | &:hover {
21 | color: var(--active-color)
22 | }
23 |
24 | &__label {
25 | font-size: 1.3rem;
26 | font-weight: 600;
27 | margin-right: .8rem;
28 | }
29 |
30 | &__pill {
31 | border: solid .1rem var(--default-color);
32 | border-radius: 2rem;
33 | width: 3.8rem;
34 | display: flex;
35 | padding: .1rem;
36 | }
37 |
38 | &__circle {
39 | fill: var(--default-color);
40 | margin-left: 0;
41 | transition: 100ms;
42 |
43 | &--active {
44 | fill: var(--active-color);
45 | margin-left: 1.8rem;
46 | }
47 | }
48 | }
49 |
50 | @media screen and (max-width: 900px) {
51 | .SoundButton {
52 | bottom: 2rem;
53 | }
54 | }
55 |
56 | @media screen and (max-width: 820px) {
57 | .SoundButton {
58 | bottom: 1.0rem;
59 | }
60 | }
--------------------------------------------------------------------------------
/src/components/UI.js:
--------------------------------------------------------------------------------
1 | import React, { useRef } from 'react';
2 | import { useSpring, useTransition, animated } from 'react-spring';
3 | import './UI.scss';
4 |
5 | export default ({ selections }) => {
6 |
7 | const ref = useRef([])
8 | const [ items, setItems ] = React.useState([]);
9 | const transitions = useTransition(items, null, {
10 | from: { transform: 'translate3d(0,-10px,0)', opacity: '0' },
11 | enter: { transform: 'translate3d(0,0px,0)', opacity: '1' },
12 | leave: { transform: 'translate3d(0,-10px,0)', opacity: '0' },
13 | config: { mass: 1, tension: 120, friction: 14 }
14 | });
15 |
16 | React.useEffect(() => {
17 | update();
18 | }, [selections]);
19 |
20 |
21 | const style = useSpring({
22 | to: {opacity: 1},
23 | from: {opacity: 0},
24 | config: { mass: 1, tension: 280, friction: 120 }
25 | })
26 |
27 |
28 | const update = () => {
29 | ref.current.map(clearTimeout)
30 | ref.current = []
31 | setItems([]);
32 | ref.current.push(setTimeout(() => setItems([getResultPhrase()]), 1000))
33 | }
34 |
35 | const getOkPhrase = () => {
36 | const phrases = [
37 | 'Ok',
38 | 'Oookay',
39 | 'Alrighty',
40 | 'Alright',
41 | 'Fine',
42 | 'Fine',
43 | ]
44 | return phrases[Math.floor(Math.random() * phrases.length)];
45 | }
46 |
47 | const getResultPhrase = () => {
48 |
49 | if(selections.length === 0) {
50 | return Pick any two...;
51 | } else if (selections.length === 1) {
52 | return Ok, pick one more...;
53 | }
54 |
55 | if(selections.every(s => s !== 'good')) {
56 | return {getOkPhrase()}, but it will be poo.;
57 | } else if(selections.every(s => s !== 'fast')) {
58 | return {getOkPhrase()}, but it will take a while.;
59 | } else if(selections.every(s => s !== 'cheap')) {
60 | return {getOkPhrase()}, but it will be expensive.
61 | }
62 | }
63 |
64 | return (
65 |
66 | How would you like your project completed?
67 | {transitions.map(({ item, props, key }) =>
68 | {item}
69 | )}
70 |
71 | )
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/src/components/UI.scss:
--------------------------------------------------------------------------------
1 | .UI {
2 | position: absolute;
3 | top: 0;
4 | left: 0;
5 | width: 50%;
6 | height: 50%;
7 | // border: solid 1px blue;
8 | color: rgba(255, 255, 255, .9);
9 | transition: 300ms;
10 | padding-left: 2rem;
11 |
12 | &__question {
13 | margin-top: 10rem;
14 | font-size: 4.2rem;
15 | font-weight: 300;
16 | }
17 |
18 | &__answer {
19 | position: absolute;
20 | bottom: 0%;
21 | font-size: 3.2rem;
22 | font-weight: 300;
23 |
24 | &--strong {
25 | font-weight: 700;
26 | color: #fff;
27 | }
28 | }
29 |
30 |
31 | }
32 |
33 | @media screen and (max-width: 1200px) {
34 | .UI {
35 | &__question {
36 | margin-top: 6rem;
37 | font-size: 3.75rem;
38 | }
39 |
40 | &__answer {
41 | font-size: 3rem;
42 | }
43 | }
44 | }
45 |
46 | @media screen and (max-width: 900px) {
47 | .UI {
48 | &__question {
49 | margin-top: 2rem;
50 | font-size: 3.5rem;
51 | }
52 |
53 | &__answer {
54 | font-size: 2.5rem;
55 | }
56 | }
57 | }
58 |
59 | @media screen and (max-width: 820px) {
60 | .UI {
61 | height: auto;
62 | width: 100%;
63 | padding: 1rem;
64 | z-index: 999;
65 |
66 | &__question {
67 | text-align: center;
68 | margin-top: 2rem;
69 | font-size: 3.5rem;
70 | }
71 |
72 | &__answer {
73 | position: static;
74 | text-align: center;
75 | width: 100%
76 | }
77 | }
78 | }
79 |
80 | @media screen and (max-width: 760px) {
81 | .UI {
82 | &__question {
83 | margin-top: 2rem;
84 | font-size: 3rem;
85 | }
86 |
87 | &__answer {
88 | font-size: 2.25rem;
89 | }
90 |
91 | }
92 | }
93 |
94 | @media screen and (max-width: 350px) {
95 | .UI {
96 | &__question {
97 | margin-top: 2rem;
98 | font-size: 2.5rem;
99 | }
100 |
101 | &__answer {
102 | font-size: 2rem;
103 | }
104 |
105 | }
106 | }
--------------------------------------------------------------------------------
/src/components/UISecondary.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import SoundButton from './SoundButton';
3 | import arrowImg from '../images/arrow-sm.png';
4 | import About from './About';
5 | import './UISecondary.scss';
6 | import { useSpring, animated as a } from 'react-spring';
7 |
8 |
9 | export default ({ toggleSound, allowSound }) => {
10 | const [modalOpen, setModalOpen] = React.useState(false);
11 |
12 | const style = useSpring({
13 | to: {opacity: 1},
14 | from: {opacity: 0},
15 | delay: 1500,
16 | config: { mass: 1, tension: 280, friction: 120 }
17 | })
18 |
19 | return (
20 |
21 |
22 |
23 | Drag to orbit
24 |
25 |
26 |
27 | )
28 | }
--------------------------------------------------------------------------------
/src/components/UISecondary.scss:
--------------------------------------------------------------------------------
1 | .UISecondary {
2 |
3 | &__about-link {
4 | position: absolute;
5 | bottom: 3rem;
6 | left: 15rem;
7 | height: 4.4rem;
8 | background: none;
9 | border: none;
10 | outline: none;
11 | color: var(--default-color);
12 | font-family: inherit;
13 | font-size: 1.3rem;
14 | font-weight: 600;
15 | transition: var(--transition-time);
16 | cursor: pointer;
17 |
18 | &:hover {
19 | color: var(--active-color)
20 | }
21 | }
22 |
23 | &__dragText {
24 | position: absolute;
25 | bottom: 4.38rem;
26 | right: 2rem;
27 | color: var(--default-color);
28 | font-family: inherit;
29 | font-size: 1.3rem;
30 | font-weight: 600;
31 | }
32 |
33 | &__dragArrow {
34 | position: absolute;
35 | opacity: .5;
36 | width: 3rem;
37 | bottom: 6.75rem;
38 | right: 4rem;
39 | transform: rotate(-80deg);
40 | }
41 | }
42 |
43 | @media screen and (max-width: 900px) {
44 | .UISecondary {
45 |
46 | &__about-link {
47 | bottom: 2rem;
48 | }
49 |
50 | &__dragText {
51 | bottom: 3.38rem;
52 | }
53 |
54 | &__dragArrow {
55 | bottom: 5.75rem;
56 | }
57 | }
58 | }
59 |
60 | @media screen and (max-width: 820px) {
61 | .UISecondary {
62 |
63 | &__about-link {
64 | bottom: 1rem;
65 | left: 13rem;
66 | }
67 |
68 | &__dragText {
69 | bottom: 2.38rem;
70 | }
71 |
72 | &__dragArrow {
73 | bottom: 4.75rem;
74 | }
75 | }
76 | }
77 |
78 |
79 | @media screen and (max-width: 400px) {
80 | .UISecondary {
81 | &__about-link {
82 | bottom: 1rem;
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/src/images/arrow-sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/images/arrow-sm.png
--------------------------------------------------------------------------------
/src/images/jon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/images/jon.jpg
--------------------------------------------------------------------------------
/src/images/propeller.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonarnold/react-threejs-good-cheap-fast/8732c361e1b70f0df21561df3adaecd45e8e0c03/src/images/propeller.png
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { render } from 'react-dom'
2 | import React from 'react'
3 | import App from './App'
4 | import './styles.css'
5 |
6 | render(, document.querySelector('#root'))
7 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --default-color: rgba(0, 0, 0, .4);
3 | --active-color: rgba(0, 0, 0, .70);
4 | --transition-time: 200ms
5 | }
6 |
7 | * {
8 | box-sizing: border-box;
9 | }
10 |
11 | html,
12 | body,
13 | #root {
14 | font-size: 62.5%;
15 | width: 100vw;
16 | height: 100vh;
17 | margin: 0;
18 | padding: 0;
19 | overflow: hidden;
20 | -webkit-font-smoothing: antialiased;
21 | -moz-osx-font-smoothing: grayscale;
22 | }
23 |
24 | body {
25 | font-family: 'Quicksand', sans-serif;
26 | color: white;
27 | background: linear-gradient(to bottom, #5f656b 0%,#93989e 67%,#d7dbe0 100%);
28 | user-select: none;
29 | }
30 | canvas {
31 | height: 100%;
32 | width: 100%;
33 | outline: none;
34 | }
35 |
36 | .App {
37 | max-width: 100rem;
38 | margin: auto;
39 | /* border: solid 1px red; */
40 | position: relative;
41 | height: 100vh;
42 | }
43 |
44 | .App__canvas {
45 | margin: 0 -10rem 0 -10rem;
46 | max-width: 80rem;
47 | /* border: solid 1px green; */
48 | position: absolute;
49 | top: 0;
50 | right: 0;
51 | height: 100vh;
52 | width: 100vw;
53 | }
54 |
55 |
56 | @media screen and (max-width: 820px) {
57 | .App__canvas {
58 | margin: 0;
59 | /* padding-top: 8rem; */
60 | max-width: 100vw;
61 | height: 100vh;
62 | width: 100vw;
63 | }
64 | }
65 |
66 | @media screen and (max-width: 500px) {
67 | .App__canvas {
68 | margin-top: 2rem;
69 | padding-bottom: 3rem;
70 | }
71 | }
72 |
73 | @media screen and (max-width: 450px) {
74 | .App__canvas {
75 | padding-top: 7rem;
76 | padding-bottom: 5rem;
77 | }
78 | }
79 |
80 | @media screen and (max-width: 450px) and (height: 800px){
81 | .App__canvas {
82 | padding-top: 0rem;
83 | padding-bottom: 0rem;
84 | }
85 | }
86 |
87 | /* @media screen and (max-width: 400px) {
88 | .App__canvas {
89 | padding-top: 15rem;
90 | padding-bottom: 12rem;
91 | }
92 | } */
--------------------------------------------------------------------------------