├── .gitignore ├── README.md ├── build ├── asset-manifest.json ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json ├── precache-manifest.183c1118394b3870f418b9fee0b2a94e.js ├── robots.txt ├── service-worker.js └── static │ └── js │ ├── 2.8e76e459.chunk.js │ ├── 2.8e76e459.chunk.js.map │ ├── main.620dc5e7.chunk.js │ ├── main.620dc5e7.chunk.js.map │ ├── runtime-main.d1b2ac6a.js │ └── runtime-main.d1b2ac6a.js.map ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.js ├── App.test.js ├── ReactTHREE.js └── index.js └── yarn.lock /.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 | 13 | # misc 14 | .DS_Store 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Demo](https://liyuanqiu.github.io/react-reconciler-three/build/) 2 | 3 | ```javascript 4 | import React from "react"; 5 | import ReactTHREE from "./ReactTHREE"; 6 | import App from "./App"; 7 | 8 | ReactTHREE.render(, document.getElementById("root")); 9 | ``` 10 | 11 | `ReactTHREE` is a custom renderer for `react`. 12 | -------------------------------------------------------------------------------- /build/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | "main.js": "/react-reconciler-three/build/static/js/main.620dc5e7.chunk.js", 4 | "main.js.map": "/react-reconciler-three/build/static/js/main.620dc5e7.chunk.js.map", 5 | "runtime-main.js": "/react-reconciler-three/build/static/js/runtime-main.d1b2ac6a.js", 6 | "runtime-main.js.map": "/react-reconciler-three/build/static/js/runtime-main.d1b2ac6a.js.map", 7 | "static/js/2.8e76e459.chunk.js": "/react-reconciler-three/build/static/js/2.8e76e459.chunk.js", 8 | "static/js/2.8e76e459.chunk.js.map": "/react-reconciler-three/build/static/js/2.8e76e459.chunk.js.map", 9 | "index.html": "/react-reconciler-three/build/index.html", 10 | "precache-manifest.183c1118394b3870f418b9fee0b2a94e.js": "/react-reconciler-three/build/precache-manifest.183c1118394b3870f418b9fee0b2a94e.js", 11 | "service-worker.js": "/react-reconciler-three/build/service-worker.js" 12 | }, 13 | "entrypoints": [ 14 | "static/js/runtime-main.d1b2ac6a.js", 15 | "static/js/2.8e76e459.chunk.js", 16 | "static/js/main.620dc5e7.chunk.js" 17 | ] 18 | } -------------------------------------------------------------------------------- /build/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyuanqiu/react-reconciler-three/c66eb9081e3f727e3258692c588380fc835d1848/build/favicon.ico -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | React App
-------------------------------------------------------------------------------- /build/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyuanqiu/react-reconciler-three/c66eb9081e3f727e3258692c588380fc835d1848/build/logo192.png -------------------------------------------------------------------------------- /build/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyuanqiu/react-reconciler-three/c66eb9081e3f727e3258692c588380fc835d1848/build/logo512.png -------------------------------------------------------------------------------- /build/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /build/precache-manifest.183c1118394b3870f418b9fee0b2a94e.js: -------------------------------------------------------------------------------- 1 | self.__precacheManifest = (self.__precacheManifest || []).concat([ 2 | { 3 | "revision": "05efa540c18ca603272747a4707be343", 4 | "url": "/react-reconciler-three/build/index.html" 5 | }, 6 | { 7 | "revision": "08054b8f8e2a42a5e7c8", 8 | "url": "/react-reconciler-three/build/static/js/2.8e76e459.chunk.js" 9 | }, 10 | { 11 | "revision": "86819e16e57e26d8bab9", 12 | "url": "/react-reconciler-three/build/static/js/main.620dc5e7.chunk.js" 13 | }, 14 | { 15 | "revision": "38c9fbe17ac6cc581614", 16 | "url": "/react-reconciler-three/build/static/js/runtime-main.d1b2ac6a.js" 17 | } 18 | ]); -------------------------------------------------------------------------------- /build/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /build/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); 15 | 16 | importScripts( 17 | "/react-reconciler-three/build/precache-manifest.183c1118394b3870f418b9fee0b2a94e.js" 18 | ); 19 | 20 | self.addEventListener('message', (event) => { 21 | if (event.data && event.data.type === 'SKIP_WAITING') { 22 | self.skipWaiting(); 23 | } 24 | }); 25 | 26 | workbox.core.clientsClaim(); 27 | 28 | /** 29 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 30 | * requests for URLs in the manifest. 31 | * See https://goo.gl/S9QRab 32 | */ 33 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 34 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 35 | 36 | workbox.routing.registerNavigationRoute(workbox.precaching.getCacheKeyForURL("/react-reconciler-three/build/index.html"), { 37 | 38 | blacklist: [/^\/_/,/\/[^\/?]+\.[^\/]+$/], 39 | }); 40 | -------------------------------------------------------------------------------- /build/static/js/main.620dc5e7.chunk.js: -------------------------------------------------------------------------------- 1 | (this["webpackJsonpreact-three"]=this["webpackJsonpreact-three"]||[]).push([[0],{10:function(e,t,n){"use strict";n.r(t);var r=n(0),a=n.n(r),i=n(3),o=n.n(i),c=n(1),s={createInstance:!0,appendChildToContainer:!0,appendChild:!0,appendInitialChild:!0,removeChildFromContainer:!0,removeChild:!0,insertInContainerBefore:!0,insertBefore:!0,prepareUpdate:!1,commitUpdate:!1};function l(e,t){!0===s[e]&&(console.log("*** ".concat(e," ***")),console.log(t))}var d=o()({supportsMutation:!0,createInstance:function(e,t,n,r,a){switch(l("createInstance",arguments),e){case"threeBoxGeometry":var i=t.width,o=t.height,s=t.depth;return new c.a(i,o,s);case"threeMeshBasicMaterial":var d=t.parameters;return new c.c(d);case"threeMesh":var h=t.rotation,u=h.x,p=h.y,m=new c.b;return void 0!==u&&(m.rotation.x=u),void 0!==p&&(m.rotation.y=p),m;case"threeScene":return new c.e;case"threePerspectiveCamera":var f=t.fov,C=t.aspect,v=t.near,x=t.far,y=t.position,w=y.x,b=y.y,B=y.z,I=new c.d(f,C,v,x);return void 0!==w&&(I.position.x=w),void 0!==b&&(I.position.y=b),void 0!==B&&(I.position.z=B),I;case"threeWebGLRenderer":var M=t.width,g=t.height,E=t.antialias,G=new c.f({antialias:E});return G.setSize(M,g),{renderer:G,scene:null,camera:null};default:return null}},createTextInstance:function(e,t,n,r){return null},appendChildToContainer:function(e,t){l("appendChildToContainer",arguments),e.appendChild(t.renderer.domElement)},appendChild:function(e,t){l("appendChild",arguments)},appendInitialChild:function(e,t){if(l("appendInitialChild",arguments),e.renderer instanceof c.f){switch(t.type){case"Scene":e.scene=t;break;case"PerspectiveCamera":e.camera=t}null!==e.scene&&null!==e.camera&&e.renderer.render(e.scene,e.camera)}switch(e.type){case"Mesh":switch(t.type){case"BoxGeometry":e.geometry=t;break;case"MeshBasicMaterial":e.material=t}break;case"Scene":e.add(t)}},removeChildFromContainer:function(e,t){l("removeChildFromContainer",arguments),e.removeChild(t.renderer.domElement)},removeChild:function(e,t){l("removeChild",arguments)},insertInContainerBefore:function(e,t,n){l("insertInContainerBefore",arguments)},insertBefore:function(e,t,n){l("insertBefore",arguments)},prepareUpdate:function(e,t,n,r,a,i){switch(l("prepareUpdate",arguments),t){case"threeWebGLRenderer":return!0;case"threeMesh":var o=n.rotation,c=o.x,s=o.y,d=r.rotation,h=d.x,u=d.y;if(c!==h||s!==u)return{rotation:r.rotation}}},commitUpdate:function(e,t,n,r,a,i){switch(l("commitUpdate",arguments),n){case"threeWebGLRenderer":if(!0===t){var o=e.renderer,c=e.scene,s=e.camera;null!==c&&null!==s&&o.render(c,s)}break;case"threeMesh":if(void 0!==t.rotation){var d=t.rotation,h=d.x,u=d.y;void 0!==h&&(e.rotation.x=h),void 0!==u&&(e.rotation.y=u)}}},finalizeInitialChildren:function(){},getChildHostContext:function(){},getPublicInstance:function(){},getRootHostContext:function(){},prepareForCommit:function(){},resetAfterCommit:function(){},shouldSetTextContent:function(){return!1}}),h=function(e,t){var n=d.createContainer(t,!1,!1);d.updateContainer(e,n,null,null)},u=n(4),p=300,m=300;var f=function(){var e=Object(r.useState)({x:0,y:0}),t=Object(u.a)(e,2),n=t[0],i=t[1];return Object(r.useEffect)((function(){var e=-1;return function t(){e=requestAnimationFrame(t),i((function(e){return{x:e.x+.01,y:e.y+.01}}))}(),function(){cancelAnimationFrame(e)}}),[]),a.a.createElement("threeWebGLRenderer",{width:p,height:m,antialias:!0},a.a.createElement("threeScene",null,a.a.createElement("threeMesh",{rotation:n},a.a.createElement("threeBoxGeometry",{width:1,height:1,depth:1}),a.a.createElement("threeMeshBasicMaterial",{parameters:{color:65280}}))),a.a.createElement("threePerspectiveCamera",{fov:75,aspect:p/m,near:.1,far:1e3,position:{z:5}}))};h(a.a.createElement(f,null),document.getElementById("root"))},5:function(e,t,n){e.exports=n(10)}},[[5,1,2]]]); 2 | //# sourceMappingURL=main.620dc5e7.chunk.js.map -------------------------------------------------------------------------------- /build/static/js/main.620dc5e7.chunk.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["ReactTHREE.js","App.js","index.js"],"names":["logConfig","createInstance","appendChildToContainer","appendChild","appendInitialChild","removeChildFromContainer","removeChild","insertInContainerBefore","insertBefore","prepareUpdate","commitUpdate","log","type","args","console","reconciler","ReactReconciler","supportsMutation","props","rootContainerInstance","hostContext","internalInstanceHandle","arguments","width","height","depth","BoxGeometry","parameters","MeshBasicMaterial","rotation","x","y","mesh","Mesh","undefined","Scene","fov","aspect","near","far","position","z","camera","PerspectiveCamera","antialias","renderer","WebGLRenderer","setSize","scene","createTextInstance","text","container","child","domElement","parent","render","geometry","material","add","before","instance","oldProps","newProps","currentHostContext","ox","oy","nx","ny","updatePayload","finishedWork","finalizeInitialChildren","getChildHostContext","getPublicInstance","getRootHostContext","prepareForCommit","resetAfterCommit","shouldSetTextContent","whatToRender","div","createContainer","updateContainer","App","useState","setRotation","useEffect","id","animate","requestAnimationFrame","prev","cancelAnimationFrame","color","ReactTHREE","document","getElementById"],"mappings":"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","file":"static/js/main.620dc5e7.chunk.js","sourcesContent":["import ReactReconciler from \"react-reconciler\";\nimport {\n BoxGeometry,\n MeshBasicMaterial,\n Mesh,\n Scene,\n PerspectiveCamera,\n WebGLRenderer\n} from \"three\";\n\nconst logConfig = {\n createInstance: true,\n appendChildToContainer: true,\n appendChild: true,\n appendInitialChild: true,\n removeChildFromContainer: true,\n removeChild: true,\n insertInContainerBefore: true,\n insertBefore: true,\n prepareUpdate: false,\n commitUpdate: false\n};\n\nfunction log(type, args) {\n if (logConfig[type] === true) {\n console.log(`*** ${type} ***`);\n console.log(args);\n }\n}\n\nlet reconciler = ReactReconciler({\n /* configuration for how to talk to the host environment */\n /* aka \"host config\" */\n\n supportsMutation: true,\n\n createInstance(\n type,\n props,\n rootContainerInstance,\n hostContext,\n internalInstanceHandle\n ) {\n log(\"createInstance\", arguments);\n switch (type) {\n case \"threeBoxGeometry\": {\n const { width, height, depth } = props;\n return new BoxGeometry(width, height, depth);\n }\n case \"threeMeshBasicMaterial\": {\n const { parameters } = props;\n return new MeshBasicMaterial(parameters);\n }\n case \"threeMesh\": {\n const {\n rotation: { x, y }\n } = props;\n const mesh = new Mesh();\n if (x !== undefined) {\n mesh.rotation.x = x;\n }\n if (y !== undefined) {\n mesh.rotation.y = y;\n }\n return mesh;\n }\n case \"threeScene\": {\n return new Scene();\n }\n case \"threePerspectiveCamera\": {\n const {\n fov,\n aspect,\n near,\n far,\n position: { x, y, z }\n } = props;\n const camera = new PerspectiveCamera(fov, aspect, near, far);\n if (x !== undefined) {\n camera.position.x = x;\n }\n if (y !== undefined) {\n camera.position.y = y;\n }\n if (z !== undefined) {\n camera.position.z = z;\n }\n return camera;\n }\n case \"threeWebGLRenderer\": {\n const { width, height, antialias } = props;\n const renderer = new WebGLRenderer({\n antialias\n });\n renderer.setSize(width, height);\n return {\n renderer,\n scene: null,\n camera: null\n };\n }\n default:\n return null;\n }\n },\n createTextInstance(\n text,\n rootContainerInstance,\n hostContext,\n internalInstanceHandle\n ) {\n return null;\n },\n\n appendChildToContainer(container, child) {\n log(\"appendChildToContainer\", arguments);\n container.appendChild(child.renderer.domElement);\n },\n appendChild(parent, child) {\n log(\"appendChild\", arguments);\n },\n appendInitialChild(parent, child) {\n log(\"appendInitialChild\", arguments);\n if (parent.renderer instanceof WebGLRenderer) {\n switch (child.type) {\n case \"Scene\":\n parent.scene = child;\n break;\n case \"PerspectiveCamera\":\n parent.camera = child;\n break;\n default:\n }\n if (parent.scene !== null && parent.camera !== null) {\n parent.renderer.render(parent.scene, parent.camera);\n }\n }\n switch (parent.type) {\n case \"Mesh\": {\n switch (child.type) {\n case \"BoxGeometry\":\n parent.geometry = child;\n break;\n case \"MeshBasicMaterial\":\n parent.material = child;\n break;\n default:\n }\n break;\n }\n case \"Scene\": {\n parent.add(child);\n break;\n }\n default:\n }\n },\n\n removeChildFromContainer(container, child) {\n log(\"removeChildFromContainer\", arguments);\n container.removeChild(child.renderer.domElement);\n },\n removeChild(parent, child) {\n log(\"removeChild\", arguments);\n },\n insertInContainerBefore(container, child, before) {\n log(\"insertInContainerBefore\", arguments);\n },\n insertBefore(parent, child, before) {\n log(\"insertBefore\", arguments);\n },\n\n prepareUpdate(\n instance,\n type,\n oldProps,\n newProps,\n rootContainerInstance,\n currentHostContext\n ) {\n log(\"prepareUpdate\", arguments);\n switch (type) {\n case \"threeWebGLRenderer\": {\n return true;\n }\n case \"threeMesh\":\n const {\n rotation: { x: ox, y: oy }\n } = oldProps;\n const {\n rotation: { x: nx, y: ny }\n } = newProps;\n if (ox !== nx || oy !== ny) {\n return {\n rotation: newProps.rotation\n };\n }\n break;\n default:\n }\n },\n commitUpdate(\n instance,\n updatePayload,\n type,\n oldProps,\n newProps,\n finishedWork\n ) {\n log(\"commitUpdate\", arguments);\n switch (type) {\n case \"threeWebGLRenderer\": {\n if (updatePayload === true) {\n const { renderer, scene, camera } = instance;\n if (scene !== null && camera !== null) {\n renderer.render(scene, camera);\n }\n }\n break;\n }\n case \"threeMesh\":\n if (updatePayload.rotation !== undefined) {\n const {\n rotation: { x, y }\n } = updatePayload;\n if (x !== undefined) {\n instance.rotation.x = x;\n }\n if (y !== undefined) {\n instance.rotation.y = y;\n }\n }\n break;\n default:\n }\n },\n\n finalizeInitialChildren() {},\n getChildHostContext() {},\n getPublicInstance() {},\n getRootHostContext() {},\n prepareForCommit() {},\n resetAfterCommit() {},\n shouldSetTextContent() {\n return false;\n }\n});\n\nexport default {\n render(whatToRender, div) {\n let container = reconciler.createContainer(div, false, false);\n reconciler.updateContainer(whatToRender, container, null, null);\n }\n};\n","/* eslint react/jsx-no-undef:0 */\nimport React, { useState, useEffect } from \"react\";\n\nconst width = 300;\nconst height = 300;\n\nfunction App() {\n const [rotation, setRotation] = useState({\n x: 0,\n y: 0\n });\n useEffect(() => {\n let id = -1;\n function animate() {\n id = requestAnimationFrame(animate);\n setRotation(prev => ({\n x: prev.x + 0.01,\n y: prev.y + 0.01\n }));\n }\n animate();\n return () => {\n cancelAnimationFrame(id);\n };\n }, []);\n return (\n \n \n \n \n \n \n \n \n \n );\n}\n\nexport default App;\n","import React from \"react\";\nimport ReactTHREE from \"./ReactTHREE\";\nimport App from \"./App\";\n\nReactTHREE.render(, document.getElementById(\"root\"));\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /build/static/js/runtime-main.d1b2ac6a.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(r){for(var n,l,a=r[0],c=r[1],i=r[2],p=0,s=[];p0.2%", 26 | "not dead", 27 | "not op_mini all" 28 | ], 29 | "development": [ 30 | "last 1 chrome version", 31 | "last 1 firefox version", 32 | "last 1 safari version" 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyuanqiu/react-reconciler-three/c66eb9081e3f727e3258692c588380fc835d1848/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyuanqiu/react-reconciler-three/c66eb9081e3f727e3258692c588380fc835d1848/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyuanqiu/react-reconciler-three/c66eb9081e3f727e3258692c588380fc835d1848/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | /* eslint react/jsx-no-undef:0 */ 2 | import React, { useState, useEffect } from "react"; 3 | 4 | const width = 300; 5 | const height = 300; 6 | 7 | function App() { 8 | const [rotation, setRotation] = useState({ 9 | x: 0, 10 | y: 0 11 | }); 12 | useEffect(() => { 13 | let id = -1; 14 | function animate() { 15 | id = requestAnimationFrame(animate); 16 | setRotation(prev => ({ 17 | x: prev.x + 0.01, 18 | y: prev.y + 0.01 19 | })); 20 | } 21 | animate(); 22 | return () => { 23 | cancelAnimationFrame(id); 24 | }; 25 | }, []); 26 | return ( 27 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 47 | 48 | ); 49 | } 50 | 51 | export default App; 52 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactTHREE from "./ReactTHREE"; 3 | import App from "./App"; 4 | 5 | it("renders without crashing", () => { 6 | const div = document.createElement("div"); 7 | ReactTHREE.render(, div); 8 | ReactTHREE.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /src/ReactTHREE.js: -------------------------------------------------------------------------------- 1 | import ReactReconciler from "react-reconciler"; 2 | import { 3 | BoxGeometry, 4 | MeshBasicMaterial, 5 | Mesh, 6 | Scene, 7 | PerspectiveCamera, 8 | WebGLRenderer 9 | } from "three"; 10 | 11 | const logConfig = { 12 | createInstance: true, 13 | appendChildToContainer: true, 14 | appendChild: true, 15 | appendInitialChild: true, 16 | removeChildFromContainer: true, 17 | removeChild: true, 18 | insertInContainerBefore: true, 19 | insertBefore: true, 20 | prepareUpdate: false, 21 | commitUpdate: false 22 | }; 23 | 24 | function log(type, args) { 25 | if (logConfig[type] === true) { 26 | console.log(`*** ${type} ***`); 27 | console.log(args); 28 | } 29 | } 30 | 31 | let reconciler = ReactReconciler({ 32 | /* configuration for how to talk to the host environment */ 33 | /* aka "host config" */ 34 | 35 | supportsMutation: true, 36 | 37 | createInstance( 38 | type, 39 | props, 40 | rootContainerInstance, 41 | hostContext, 42 | internalInstanceHandle 43 | ) { 44 | log("createInstance", arguments); 45 | switch (type) { 46 | case "threeBoxGeometry": { 47 | const { width, height, depth } = props; 48 | return new BoxGeometry(width, height, depth); 49 | } 50 | case "threeMeshBasicMaterial": { 51 | const { parameters } = props; 52 | return new MeshBasicMaterial(parameters); 53 | } 54 | case "threeMesh": { 55 | const { 56 | rotation: { x, y } 57 | } = props; 58 | const mesh = new Mesh(); 59 | if (x !== undefined) { 60 | mesh.rotation.x = x; 61 | } 62 | if (y !== undefined) { 63 | mesh.rotation.y = y; 64 | } 65 | return mesh; 66 | } 67 | case "threeScene": { 68 | return new Scene(); 69 | } 70 | case "threePerspectiveCamera": { 71 | const { 72 | fov, 73 | aspect, 74 | near, 75 | far, 76 | position: { x, y, z } 77 | } = props; 78 | const camera = new PerspectiveCamera(fov, aspect, near, far); 79 | if (x !== undefined) { 80 | camera.position.x = x; 81 | } 82 | if (y !== undefined) { 83 | camera.position.y = y; 84 | } 85 | if (z !== undefined) { 86 | camera.position.z = z; 87 | } 88 | return camera; 89 | } 90 | case "threeWebGLRenderer": { 91 | const { width, height, antialias } = props; 92 | const renderer = new WebGLRenderer({ 93 | antialias 94 | }); 95 | renderer.setSize(width, height); 96 | return { 97 | renderer, 98 | scene: null, 99 | camera: null 100 | }; 101 | } 102 | default: 103 | return null; 104 | } 105 | }, 106 | createTextInstance( 107 | text, 108 | rootContainerInstance, 109 | hostContext, 110 | internalInstanceHandle 111 | ) { 112 | return null; 113 | }, 114 | 115 | appendChildToContainer(container, child) { 116 | log("appendChildToContainer", arguments); 117 | container.appendChild(child.renderer.domElement); 118 | }, 119 | appendChild(parent, child) { 120 | log("appendChild", arguments); 121 | }, 122 | appendInitialChild(parent, child) { 123 | log("appendInitialChild", arguments); 124 | if (parent.renderer instanceof WebGLRenderer) { 125 | switch (child.type) { 126 | case "Scene": 127 | parent.scene = child; 128 | break; 129 | case "PerspectiveCamera": 130 | parent.camera = child; 131 | break; 132 | default: 133 | } 134 | if (parent.scene !== null && parent.camera !== null) { 135 | parent.renderer.render(parent.scene, parent.camera); 136 | } 137 | } 138 | switch (parent.type) { 139 | case "Mesh": { 140 | switch (child.type) { 141 | case "BoxGeometry": 142 | parent.geometry = child; 143 | break; 144 | case "MeshBasicMaterial": 145 | parent.material = child; 146 | break; 147 | default: 148 | } 149 | break; 150 | } 151 | case "Scene": { 152 | parent.add(child); 153 | break; 154 | } 155 | default: 156 | } 157 | }, 158 | 159 | removeChildFromContainer(container, child) { 160 | log("removeChildFromContainer", arguments); 161 | container.removeChild(child.renderer.domElement); 162 | }, 163 | removeChild(parent, child) { 164 | log("removeChild", arguments); 165 | }, 166 | insertInContainerBefore(container, child, before) { 167 | log("insertInContainerBefore", arguments); 168 | }, 169 | insertBefore(parent, child, before) { 170 | log("insertBefore", arguments); 171 | }, 172 | 173 | prepareUpdate( 174 | instance, 175 | type, 176 | oldProps, 177 | newProps, 178 | rootContainerInstance, 179 | currentHostContext 180 | ) { 181 | log("prepareUpdate", arguments); 182 | switch (type) { 183 | case "threeWebGLRenderer": { 184 | return true; 185 | } 186 | case "threeMesh": 187 | const { 188 | rotation: { x: ox, y: oy } 189 | } = oldProps; 190 | const { 191 | rotation: { x: nx, y: ny } 192 | } = newProps; 193 | if (ox !== nx || oy !== ny) { 194 | return { 195 | rotation: newProps.rotation 196 | }; 197 | } 198 | break; 199 | default: 200 | } 201 | }, 202 | commitUpdate( 203 | instance, 204 | updatePayload, 205 | type, 206 | oldProps, 207 | newProps, 208 | finishedWork 209 | ) { 210 | log("commitUpdate", arguments); 211 | switch (type) { 212 | case "threeWebGLRenderer": { 213 | if (updatePayload === true) { 214 | const { renderer, scene, camera } = instance; 215 | if (scene !== null && camera !== null) { 216 | renderer.render(scene, camera); 217 | } 218 | } 219 | break; 220 | } 221 | case "threeMesh": 222 | if (updatePayload.rotation !== undefined) { 223 | const { 224 | rotation: { x, y } 225 | } = updatePayload; 226 | if (x !== undefined) { 227 | instance.rotation.x = x; 228 | } 229 | if (y !== undefined) { 230 | instance.rotation.y = y; 231 | } 232 | } 233 | break; 234 | default: 235 | } 236 | }, 237 | 238 | finalizeInitialChildren() {}, 239 | getChildHostContext() {}, 240 | getPublicInstance() {}, 241 | getRootHostContext() {}, 242 | prepareForCommit() {}, 243 | resetAfterCommit() {}, 244 | shouldSetTextContent() { 245 | return false; 246 | } 247 | }); 248 | 249 | export default { 250 | render(whatToRender, div) { 251 | let container = reconciler.createContainer(div, false, false); 252 | reconciler.updateContainer(whatToRender, container, null, null); 253 | } 254 | }; 255 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactTHREE from "./ReactTHREE"; 3 | import App from "./App"; 4 | 5 | ReactTHREE.render(, document.getElementById("root")); 6 | --------------------------------------------------------------------------------