├── .gitattributes ├── .gitignore ├── .metadata ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── docs ├── assets │ ├── AssetManifest.json │ ├── FontManifest.json │ ├── LICENSE │ ├── fonts │ │ └── MaterialIcons-Regular.ttf │ └── packages │ │ └── cupertino_icons │ │ └── assets │ │ └── CupertinoIcons.ttf ├── flutter_service_worker.js ├── icons │ ├── Icon-192.png │ └── Icon-512.png ├── index.html ├── main.dart.js ├── main.dart.js.map ├── manifest.json ├── nyanlooped.ogg └── nyanslow.ogg ├── flutter_meta.json ├── lib ├── main.dart ├── src │ └── babylon │ │ └── babylon.d.ts └── ui │ └── home │ └── screen.dart ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart └── web ├── icons ├── Icon-192.png └── Icon-512.png ├── index.html ├── manifest.json ├── nyanlooped.ogg └── nyanslow.ogg /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: ec1044a8773e31b4630bf162d9c374236ad1eaaf 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter", 9 | "request": "launch", 10 | "type": "dart" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rody Davis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_webxr_threejs 2 | 3 | An example of how to use Flutter in WebXR with ThreeJS 4 | 5 | ## Getting Started 6 | 7 | Online Demo: https://rodydavis.github.io/FlutterWebXRThreeJS/ 8 | 9 | JS Facade Gen: https://github.com/dart-lang/js_facade_gen 10 | ThreeJS in Dart: https://github.com/rodydavis/threejs-dart-facade 11 | ThreeJS: https://threejs.org/ -------------------------------------------------------------------------------- /docs/assets/AssetManifest.json: -------------------------------------------------------------------------------- 1 | {"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"]} -------------------------------------------------------------------------------- /docs/assets/FontManifest.json: -------------------------------------------------------------------------------- 1 | [{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.ttf"}]},{"family":"packages/cupertino_icons/CupertinoIcons","fonts":[{"asset":"packages/cupertino_icons/assets/CupertinoIcons.ttf"}]}] -------------------------------------------------------------------------------- /docs/assets/fonts/MaterialIcons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/docs/assets/fonts/MaterialIcons-Regular.ttf -------------------------------------------------------------------------------- /docs/assets/packages/cupertino_icons/assets/CupertinoIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/docs/assets/packages/cupertino_icons/assets/CupertinoIcons.ttf -------------------------------------------------------------------------------- /docs/flutter_service_worker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const CACHE_NAME = 'flutter-app-cache'; 3 | const RESOURCES = { 4 | "/nyanslow.ogg": "f1f43d9ad677fb8ec0bf069405e467b0", 5 | "/index.html": "3a31fe87b68e795b52e04980fc1291fb", 6 | "/nyanlooped.ogg": "7e6c1d5b03b3f2b5f318c4aeb6bc8394", 7 | "/main.dart.js": "c30eeacb703c81a3118d21c5a0458f13", 8 | "/icons/Icon-192.png": "ac9a721a12bbc803b44f645561ecb1e1", 9 | "/icons/Icon-512.png": "96e752610906ba2a93c65f8abe1645f1", 10 | "/manifest.json": "2346276c0909f129d21ba17b06c1e91d", 11 | "/assets/LICENSE": "f10b2fc0f812779064f8a13821be77f3", 12 | "/assets/AssetManifest.json": "2efbb41d7877d10aac9d091f58ccd7b9", 13 | "/assets/FontManifest.json": "01700ba55b08a6141f33e168c4a6c22f", 14 | "/assets/packages/cupertino_icons/assets/CupertinoIcons.ttf": "115e937bb829a890521f72d2e664b632", 15 | "/assets/fonts/MaterialIcons-Regular.ttf": "56d3ffdef7a25659eab6a68a3fbfaf16" 16 | }; 17 | 18 | self.addEventListener('activate', function (event) { 19 | event.waitUntil( 20 | caches.keys().then(function (cacheName) { 21 | return caches.delete(cacheName); 22 | }).then(function (_) { 23 | return caches.open(CACHE_NAME); 24 | }).then(function (cache) { 25 | return cache.addAll(Object.keys(RESOURCES)); 26 | }) 27 | ); 28 | }); 29 | 30 | self.addEventListener('fetch', function (event) { 31 | event.respondWith( 32 | caches.match(event.request) 33 | .then(function (response) { 34 | if (response) { 35 | return response; 36 | } 37 | return fetch(event.request, { 38 | credentials: 'include' 39 | }); 40 | }) 41 | ); 42 | }); 43 | -------------------------------------------------------------------------------- /docs/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/docs/icons/Icon-192.png -------------------------------------------------------------------------------- /docs/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/docs/icons/Icon-512.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | flutter_webxr_threejs 18 | 19 | 73 | 74 | 75 | 76 | 102 | 105 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /docs/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flutter_webxr_threejs", 3 | "short_name": "flutter_webxr_threejs", 4 | "start_url": ".", 5 | "display": "minimal-ui", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "An example of how to use Flutter in WebXR with ThreeJS", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /docs/nyanlooped.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/docs/nyanlooped.ogg -------------------------------------------------------------------------------- /docs/nyanslow.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/docs/nyanslow.ogg -------------------------------------------------------------------------------- /flutter_meta.json: -------------------------------------------------------------------------------- 1 | "{\"name\":\"flutter_webxr_threejs\",\"org\":\"com.rodydavis\",\"isSwift\":true,\"isKotlin\":true,\"description\":\"An example of how to use Flutter in WebXR with ThreeJS\",\"themeOptions\":null,\"navigationOptions\":null}" -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'ui/home/screen.dart'; 4 | 5 | void main() => runApp(MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | title: 'Flutter 3D Demo', 12 | theme: ThemeData.light(), 13 | darkTheme: ThemeData.dark(), 14 | home: HomeScreen(), 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/ui/home/screen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:html'; 2 | import 'dart:js' as js; 3 | import 'dart:math' as Math; 4 | import 'dart:ui' as ui; 5 | 6 | import 'package:flutter/material.dart'; 7 | import 'package:threejs_facade/three.dart'; 8 | 9 | class HomeScreen extends StatefulWidget { 10 | @override 11 | _HomeScreenState createState() => _HomeScreenState(); 12 | } 13 | 14 | class _HomeScreenState extends State { 15 | @override 16 | void initState() { 17 | song = _addAudio("nyanlooped.ogg", true); 18 | song2 = _addAudio("nyanslow.ogg", false); 19 | document.onMouseMove.listen(onDocumentMouseMove); 20 | document.onMouseDown.listen(onDocumentMouseDown); 21 | WidgetsBinding.instance.addPostFrameCallback((_) { 22 | final _size = MediaQuery.of(context).size; 23 | init(_size); 24 | animate(0); 25 | }); 26 | super.initState(); 27 | } 28 | 29 | AudioElement _addAudio(String src, [bool play = false]) { 30 | final _element = AudioElement(); 31 | // ignore: undefined_prefixed_name 32 | ui.platformViewRegistry.registerViewFactory('audio-$src', (int viewId) { 33 | _element 34 | ..style.border = '0' 35 | ..src = src 36 | ..loop = true; 37 | if (src != null) { 38 | _element..src = src; 39 | } 40 | return _element; 41 | }); 42 | if (play) { 43 | return _element; 44 | } 45 | return _element; 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return LayoutBuilder( 51 | builder: (_, dimens) { 52 | _updateSize(Size(dimens.maxWidth, dimens.maxHeight)); 53 | return Container(); 54 | }, 55 | ); 56 | } 57 | } 58 | 59 | void playAudio(String path, [bool second = false]) { 60 | js.context.callMethod('playAudio${second ? '2' : '1'}', [path]); 61 | } 62 | 63 | void pauseAudio(String path, [bool second = false]) { 64 | js.context.callMethod('pauseAudio${second ? '2' : '1'}', [path]); 65 | } 66 | 67 | Math.Random rand = Math.Random(); 68 | 69 | DivElement container; 70 | WebGLRenderer renderer; 71 | Scene scene; 72 | PerspectiveCamera camera; 73 | 74 | Object3D poptart; 75 | Object3D feet; 76 | Object3D face; 77 | Object3D tail; 78 | 79 | List stars; 80 | num numStars = 10; 81 | 82 | Object3D rainbow; 83 | Object3D rainChunk; 84 | num numRainChunks = 30; 85 | 86 | num mouseX = 0; 87 | num mouseY = 0; 88 | num windowHalfX = window.innerWidth / 2; 89 | num windowHalfY = window.innerHeight / 2; 90 | 91 | num deltaSum = 0; 92 | num tick = 0; 93 | num frame = 0; 94 | bool running = true; 95 | 96 | AudioElement song; 97 | AudioElement song2; 98 | 99 | void init(Size windowSize) { 100 | container = new DivElement(); 101 | document.body.children.add(container); 102 | 103 | camera = new PerspectiveCamera( 104 | 45.0, window.innerWidth / window.innerHeight, 0.1, 10000.0); 105 | camera.position.z = 30.0; 106 | camera.position.x = 0.0; 107 | camera.position.y = 0.0; 108 | 109 | scene = new Scene(); 110 | // TODO: FogExp2 does not inherit correctly. 111 | scene.fog = new FogExp2(0x003366, 0.0095); 112 | 113 | //POPTART 114 | poptart = new Object3D(); 115 | // object x y z w h d color 116 | helper(poptart, 0, -2, -1, 21, 14, 3, 0x222222); 117 | helper(poptart, 1, -1, -1, 19, 16, 3, 0x222222); 118 | helper(poptart, 2, 0, -1, 17, 18, 3, 0x222222); 119 | 120 | helper(poptart, 1, -2, -1.5, 19, 14, 4, 0xffcc99); 121 | helper(poptart, 2, -1, -1.5, 17, 16, 4, 0xffcc99); 122 | 123 | helper(poptart, 2, -4, 2, 17, 10, .6, 0xff99ff); 124 | helper(poptart, 3, -3, 2, 15, 12, .6, 0xff99ff); 125 | helper(poptart, 4, -2, 2, 13, 14, .6, 0xff99ff); 126 | 127 | helper(poptart, 4, -4, 2, 1, 1, .7, 0xff3399); 128 | helper(poptart, 9, -3, 2, 1, 1, .7, 0xff3399); 129 | helper(poptart, 12, -3, 2, 1, 1, .7, 0xff3399); 130 | helper(poptart, 16, -5, 2, 1, 1, .7, 0xff3399); 131 | helper(poptart, 8, -7, 2, 1, 1, .7, 0xff3399); 132 | helper(poptart, 5, -9, 2, 1, 1, .7, 0xff3399); 133 | helper(poptart, 9, -10, 2, 1, 1, .7, 0xff3399); 134 | helper(poptart, 3, -11, 2, 1, 1, .7, 0xff3399); 135 | helper(poptart, 7, -13, 2, 1, 1, .7, 0xff3399); 136 | helper(poptart, 4, -14, 2, 1, 1, .7, 0xff3399); 137 | 138 | poptart.position.x = -10.5; 139 | poptart.position.y = 9.0; 140 | scene.add(poptart); 141 | 142 | //FEET 143 | feet = new Object3D(); 144 | helper(feet, 0, -2, .49, 3, 3, 1, 0x222222); 145 | helper(feet, 1, -1, .49, 3, 3, 1, 0x222222); 146 | helper(feet, 1, -2, -.01, 2, 2, 2, 0x999999); 147 | helper(feet, 2, -1, -.01, 2, 2, 2, 0x999999); 148 | 149 | helper(feet, 6, -2, -.5, 3, 3, 1, 0x222222); 150 | helper(feet, 6, -2, -.5, 4, 2, 1, 0x222222); 151 | helper(feet, 7, -2, -.99, 2, 2, 2, 0x999999); 152 | 153 | helper(feet, 16, -3, .49, 3, 2, 1, 0x222222); 154 | helper(feet, 15, -2, .49, 3, 2, 1, 0x222222); 155 | helper(feet, 15, -2, -.01, 2, 1, 2, 0x999999); 156 | helper(feet, 16, -3, -.01, 2, 1, 2, 0x999999); 157 | 158 | helper(feet, 21, -3, -.5, 3, 2, 1, 0x222222); 159 | helper(feet, 20, -2, -.5, 3, 2, 1, 0x222222); 160 | helper(feet, 20, -2, -.99, 2, 1, 2, 0x999999); 161 | helper(feet, 21, -3, -.99, 2, 1, 2, 0x999999); 162 | 163 | feet.position.x = -12.5; 164 | feet.position.y = -6.0; 165 | scene.add(feet); 166 | 167 | //TAIL 168 | tail = new Object3D(); 169 | helper(tail, 0, 0, -.25, 4, 3, 1.5, 0x222222); 170 | helper(tail, 1, -1, -.25, 4, 3, 1.5, 0x222222); 171 | helper(tail, 2, -2, -.25, 4, 3, 1.5, 0x222222); 172 | helper(tail, 3, -3, -.25, 4, 3, 1.5, 0x222222); 173 | helper(tail, 1, -1, -.5, 2, 1, 2, 0x999999); 174 | helper(tail, 2, -2, -.5, 2, 1, 2, 0x999999); 175 | helper(tail, 3, -3, -.5, 2, 1, 2, 0x999999); 176 | helper(tail, 4, -4, -.5, 2, 1, 2, 0x999999); 177 | 178 | tail.position.x = -16.5; 179 | tail.position.y = 2.0; 180 | scene.add(tail); 181 | 182 | //FACE 183 | face = new Object3D(); 184 | helper(face, 2, -3, -3, 12, 9, 4, 0x222222); 185 | helper(face, 0, -5, 0, 16, 5, 1, 0x222222); 186 | helper(face, 1, -1, 0, 4, 10, 1, 0x222222); 187 | helper(face, 11, -1, 0, 4, 10, 1, 0x222222); 188 | helper(face, 3, -11, 0, 10, 2, 1, 0x222222); 189 | helper(face, 2, 0, 0, 2, 2, 1, 0x222222); 190 | helper(face, 4, -2, 0, 2, 2, 1, 0x222222); 191 | helper(face, 12, 0, 0, 2, 2, 1, 0x222222); 192 | helper(face, 10, -2, 0, 2, 2, 1, 0x222222); 193 | 194 | helper(face, 1, -5, .5, 14, 5, 1, 0x999999); 195 | helper(face, 3, -4, .5, 10, 8, 1, 0x999999); 196 | helper(face, 2, -1, .5, 2, 10, 1, 0x999999); 197 | helper(face, 12, -1, .5, 2, 10, 1, 0x999999); 198 | helper(face, 4, -2, .5, 1, 2, 1, 0x999999); 199 | helper(face, 5, -3, .5, 1, 1, 1, 0x999999); 200 | helper(face, 11, -2, .5, 1, 2, 1, 0x999999); 201 | helper(face, 10, -3, .5, 1, 1, 1, 0x999999); 202 | //Eyes 203 | helper(face, 4, -6, .6, 2, 2, 1, 0x222222); 204 | helper(face, 11, -6, .6, 2, 2, 1, 0x222222); 205 | helper(face, 3.99, -5.99, .6, 1.01, 1.01, 1.01, 0xffffff); 206 | helper(face, 10.99, -5.99, .6, 1.01, 1.01, 1.01, 0xffffff); 207 | //MOUTH 208 | helper(face, 5, -10, .6, 7, 1, 1, 0x222222); 209 | helper(face, 5, -9, .6, 1, 2, 1, 0x222222); 210 | helper(face, 8, -9, .6, 1, 2, 1, 0x222222); 211 | helper(face, 11, -9, .6, 1, 2, 1, 0x222222); 212 | //CHEEKS 213 | helper(face, 2, -8, .6, 2, 2, .91, 0xff9999); 214 | helper(face, 13, -8, .6, 2, 2, .91, 0xff9999); 215 | 216 | face.position.x = -.5; 217 | face.position.y = 4.0; 218 | face.position.z = 4.0; 219 | scene.add(face); 220 | 221 | //RAINBOW 222 | rainbow = new Object3D(); 223 | for (var c = 0; c < numRainChunks - 1; c++) { 224 | var yOffset = 8; 225 | if (c % 2 == 1) yOffset = 7; 226 | var xOffset = (-c * 8) - 16.5; 227 | helper(rainbow, xOffset, yOffset, 0, 8, 3, 1, 0xff0000); 228 | helper(rainbow, xOffset, yOffset - 3, 0, 8, 3, 1, 0xff9900); 229 | helper(rainbow, xOffset, yOffset - 6, 0, 8, 3, 1, 0xffff00); 230 | helper(rainbow, xOffset, yOffset - 9, 0, 8, 3, 1, 0x33ff00); 231 | helper(rainbow, xOffset, yOffset - 12, 0, 8, 3, 1, 0x0099ff); 232 | helper(rainbow, xOffset, yOffset - 15, 0, 8, 3, 1, 0x6633ff); 233 | } 234 | scene.add(rainbow); 235 | 236 | rainChunk = new Object3D(); 237 | helper(rainChunk, -16.5, 7, 0, 8, 3, 1, 0xff0000); 238 | helper(rainChunk, -16.5, 4, 0, 8, 3, 1, 0xff9900); 239 | helper(rainChunk, -16.5, 1, 0, 8, 3, 1, 0xffff00); 240 | helper(rainChunk, -16.5, -2, 0, 8, 3, 1, 0x33ff00); 241 | helper(rainChunk, -16.5, -5, 0, 8, 3, 1, 0x0099ff); 242 | helper(rainChunk, -16.5, -8, 0, 8, 3, 1, 0x6633ff); 243 | rainChunk.position.x -= (8 * (numRainChunks - 1)); 244 | scene.add(rainChunk); 245 | 246 | stars = new List(); 247 | for (var state = 0; state < 6; state++) { 248 | stars.add(new List()); 249 | for (var c = 0; c < numStars; c++) { 250 | var star = new Object3D(); 251 | star.position.x = rand.nextDouble() * 200 - 100; 252 | star.position.y = rand.nextDouble() * 200 - 100; 253 | star.position.z = rand.nextDouble() * 200 - 100; 254 | buildStar(star, state); 255 | scene.add(star); 256 | stars[state].add(star); 257 | } 258 | } 259 | 260 | var pointLight = new PointLight(0xFFFFFF); 261 | pointLight.position.z = 1000.0; 262 | scene.add(pointLight); 263 | 264 | renderer = new WebGLRenderer(); 265 | _updateSize(windowSize); 266 | container.nodes.add(renderer.domElement); 267 | } 268 | 269 | void _updateSize(ui.Size windowSize) { 270 | if (renderer != null) { 271 | renderer.setSize(windowSize.width, windowSize.height, true); 272 | } 273 | } 274 | 275 | void animate(num t) { 276 | window.requestAnimationFrame(animate); 277 | render(t); 278 | } 279 | 280 | void render(num t) { 281 | var delta = t; //clock.getDelta(); 282 | if (running) deltaSum += delta; 283 | if (deltaSum > .07) { 284 | deltaSum = deltaSum % .07; 285 | frame = (frame + 1) % 12; 286 | for (var c = 0; c < numStars; c++) { 287 | var tempX = stars[5][c].position.x, 288 | tempY = stars[5][c].position.y, 289 | tempZ = stars[5][c].position.z; 290 | for (var state = 5; state > 0; state--) { 291 | var star = stars[state][c]; 292 | var star2 = stars[state - 1][c]; 293 | star.position.x = star2.position.x - 8; 294 | star.position.y = star2.position.y; 295 | star.position.z = star2.position.z; 296 | 297 | if (star.position.x < -100) { 298 | star.position.x += 200; 299 | star.position.y = rand.nextDouble() * 200 - 100; 300 | star.position.z = rand.nextDouble() * 200 - 100; 301 | } 302 | } 303 | stars[0][c].position.x = tempX; 304 | stars[0][c].position.y = tempY; 305 | stars[0][c].position.z = tempZ; 306 | } 307 | switch (frame) { 308 | case 0: //2nd frame 309 | face.position.x++; 310 | feet.position.x++; 311 | break; 312 | case 1: 313 | face.position.y--; 314 | feet.position.x++; 315 | feet.position.y--; 316 | poptart.position.y--; 317 | rainbow.position.x -= 9.0; 318 | rainChunk.position.x += (8.0 * (numRainChunks - 1)) - 1; 319 | break; 320 | case 2: 321 | feet.position.x--; 322 | break; 323 | case 3: 324 | face.position.x--; 325 | feet.position.x--; 326 | rainbow.position.x += 9.0; 327 | rainChunk.position.x -= (8.0 * (numRainChunks - 1)) - 1; 328 | break; 329 | case 4: 330 | face.position.y++; 331 | break; 332 | case 5: 333 | poptart.position.y++; 334 | feet.position.y++; 335 | rainbow.position.x -= 9.0; 336 | rainChunk.position.x += (8.0 * (numRainChunks - 1)) - 1; 337 | break; 338 | case 6: //8th frame 339 | face.position.x++; 340 | feet.position.x++; 341 | break; 342 | case 7: 343 | poptart.position.y--; 344 | face.position.y--; 345 | feet.position.x++; 346 | feet.position.y--; 347 | rainbow.position.x += 9.0; 348 | rainChunk.position.x -= (8.0 * (numRainChunks - 1)) - 1; 349 | break; 350 | case 8: 351 | feet.position.x--; 352 | break; 353 | case 9: 354 | face.position.x--; 355 | feet.position.x--; 356 | rainbow.position.x -= 9.0; 357 | rainChunk.position.x += (8.0 * (numRainChunks - 1)) - 1; 358 | break; 359 | case 10: 360 | face.position.y++; 361 | break; 362 | case 11: //1st frame 363 | poptart.position.y++; 364 | feet.position.y++; 365 | rainbow.position.x += 9.0; 366 | rainChunk.position.x -= (8.0 * (numRainChunks - 1)) - 1; 367 | break; 368 | } 369 | } 370 | camera.position.x += (mouseX - camera.position.x) * .005; 371 | camera.position.y += (-mouseY - camera.position.y) * .005; 372 | camera.lookAt(scene.position); 373 | renderer.render(scene, camera, null, false); 374 | } 375 | 376 | void helper(o, x, y, z, w, h, d, c) { 377 | MeshLambertMaterialParameters mat = new MeshLambertMaterialParameters() 378 | ..color = c; 379 | var material = new MeshLambertMaterial(mat); 380 | var geometry = 381 | new BoxGeometry(w.toDouble(), h.toDouble(), d.toDouble(), 1, 1, 1); 382 | var mesh = new Mesh(geometry, material); 383 | mesh.position.x = x.toDouble() + (w.toDouble() / 2.0); 384 | mesh.position.y = y.toDouble() - (h.toDouble() / 2.0); 385 | mesh.position.z = z.toDouble() + (d.toDouble() / 2.0); 386 | o.add(mesh); 387 | } 388 | 389 | void buildStar(star, state) { 390 | switch (state) { 391 | case 0: 392 | helper(star, 0, 0, 0, 1, 1, 1, 0xffffff); 393 | break; 394 | case 1: 395 | helper(star, 1, 0, 0, 1, 1, 1, 0xffffff); 396 | helper(star, -1, 0, 0, 1, 1, 1, 0xffffff); 397 | helper(star, 0, 1, 0, 1, 1, 1, 0xffffff); 398 | helper(star, 0, -1, 0, 1, 1, 1, 0xffffff); 399 | break; 400 | case 2: 401 | helper(star, 1, 0, 0, 2, 1, 1, 0xffffff); 402 | helper(star, -2, 0, 0, 2, 1, 1, 0xffffff); 403 | helper(star, 0, 2, 0, 1, 2, 1, 0xffffff); 404 | helper(star, 0, -1, 0, 1, 2, 1, 0xffffff); 405 | break; 406 | case 3: 407 | helper(star, 0, 0, 0, 1, 1, 1, 0xffffff); 408 | helper(star, 2, 0, 0, 2, 1, 1, 0xffffff); 409 | helper(star, -3, 0, 0, 2, 1, 1, 0xffffff); 410 | helper(star, 0, 3, 0, 1, 2, 1, 0xffffff); 411 | helper(star, 0, -2, 0, 1, 2, 1, 0xffffff); 412 | break; 413 | case 4: 414 | helper(star, 0, 3, 0, 1, 1, 1, 0xffffff); 415 | helper(star, 2, 2, 0, 1, 1, 1, 0xffffff); 416 | helper(star, 3, 0, 0, 1, 1, 1, 0xffffff); 417 | helper(star, 2, -2, 0, 1, 1, 1, 0xffffff); 418 | helper(star, 0, -3, 0, 1, 1, 1, 0xffffff); 419 | helper(star, -2, -2, 0, 1, 1, 1, 0xffffff); 420 | helper(star, -3, 0, 0, 1, 1, 1, 0xffffff); 421 | helper(star, -2, 2, 0, 1, 1, 1, 0xffffff); 422 | break; 423 | case 5: 424 | helper(star, 2, 0, 0, 1, 1, 1, 0xffffff); 425 | helper(star, -2, 0, 0, 1, 1, 1, 0xffffff); 426 | helper(star, 0, 2, 0, 1, 1, 1, 0xffffff); 427 | helper(star, 0, -2, 0, 1, 1, 1, 0xffffff); 428 | break; 429 | } 430 | } 431 | 432 | void onDocumentMouseMove(event) { 433 | mouseX = (event.client.x - windowHalfX); 434 | mouseY = (event.client.y - windowHalfY); 435 | // print("mouseX: $mouseX, mouseY: $mouseY"); 436 | } 437 | 438 | void onDocumentMouseDown(event) { 439 | running = !running; 440 | if (running) { 441 | playAudio("nyanlooped.ogg"); 442 | pauseAudio("nyanslow.ogg", true); 443 | // song.play(); 444 | // song2.pause(); 445 | } else { 446 | pauseAudio("nyanlooped.ogg"); 447 | playAudio("nyanslow.ogg", true); 448 | // song.pause(); 449 | // song2.play(); 450 | } 451 | } 452 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | archive: 5 | dependency: transitive 6 | description: 7 | name: archive 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.0.11" 11 | args: 12 | dependency: transitive 13 | description: 14 | name: args 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.5.2" 18 | async: 19 | dependency: transitive 20 | description: 21 | name: async 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.4.0" 25 | boolean_selector: 26 | dependency: transitive 27 | description: 28 | name: boolean_selector 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.0.5" 32 | charcode: 33 | dependency: transitive 34 | description: 35 | name: charcode 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.2" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.14.11" 46 | convert: 47 | dependency: transitive 48 | description: 49 | name: convert 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "2.1.1" 53 | crypto: 54 | dependency: transitive 55 | description: 56 | name: crypto 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "2.1.3" 60 | cupertino_icons: 61 | dependency: "direct main" 62 | description: 63 | name: cupertino_icons 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "0.1.3" 67 | flutter: 68 | dependency: "direct main" 69 | description: flutter 70 | source: sdk 71 | version: "0.0.0" 72 | flutter_test: 73 | dependency: "direct dev" 74 | description: flutter 75 | source: sdk 76 | version: "0.0.0" 77 | func2: 78 | dependency: transitive 79 | description: 80 | name: func2 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "2.0.1" 84 | image: 85 | dependency: transitive 86 | description: 87 | name: image 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "2.1.4" 91 | js: 92 | dependency: transitive 93 | description: 94 | name: js 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "0.6.1+1" 98 | matcher: 99 | dependency: transitive 100 | description: 101 | name: matcher 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "0.12.6" 105 | meta: 106 | dependency: transitive 107 | description: 108 | name: meta 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "1.1.8" 112 | path: 113 | dependency: transitive 114 | description: 115 | name: path 116 | url: "https://pub.dartlang.org" 117 | source: hosted 118 | version: "1.6.4" 119 | pedantic: 120 | dependency: transitive 121 | description: 122 | name: pedantic 123 | url: "https://pub.dartlang.org" 124 | source: hosted 125 | version: "1.8.0+1" 126 | petitparser: 127 | dependency: transitive 128 | description: 129 | name: petitparser 130 | url: "https://pub.dartlang.org" 131 | source: hosted 132 | version: "2.4.0" 133 | quiver: 134 | dependency: transitive 135 | description: 136 | name: quiver 137 | url: "https://pub.dartlang.org" 138 | source: hosted 139 | version: "2.0.5" 140 | sky_engine: 141 | dependency: transitive 142 | description: flutter 143 | source: sdk 144 | version: "0.0.99" 145 | source_span: 146 | dependency: transitive 147 | description: 148 | name: source_span 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "1.5.5" 152 | stack_trace: 153 | dependency: transitive 154 | description: 155 | name: stack_trace 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "1.9.3" 159 | stream_channel: 160 | dependency: transitive 161 | description: 162 | name: stream_channel 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "2.0.0" 166 | string_scanner: 167 | dependency: transitive 168 | description: 169 | name: string_scanner 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "1.0.5" 173 | term_glyph: 174 | dependency: transitive 175 | description: 176 | name: term_glyph 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "1.1.0" 180 | test_api: 181 | dependency: transitive 182 | description: 183 | name: test_api 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "0.2.11" 187 | threejs_facade: 188 | dependency: "direct main" 189 | description: 190 | path: "." 191 | ref: HEAD 192 | resolved-ref: b97977372b52cb1eebb4593fa8373ba37a4e41d8 193 | url: "https://github.com/rodydavis/threejs-dart-facade" 194 | source: git 195 | version: "0.2.0-dev" 196 | typed_data: 197 | dependency: transitive 198 | description: 199 | name: typed_data 200 | url: "https://pub.dartlang.org" 201 | source: hosted 202 | version: "1.1.6" 203 | vector_math: 204 | dependency: transitive 205 | description: 206 | name: vector_math 207 | url: "https://pub.dartlang.org" 208 | source: hosted 209 | version: "2.0.8" 210 | xml: 211 | dependency: transitive 212 | description: 213 | name: xml 214 | url: "https://pub.dartlang.org" 215 | source: hosted 216 | version: "3.5.0" 217 | sdks: 218 | dart: ">=2.4.0 <3.0.0" 219 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_webxr_threejs 2 | description: An example of how to use Flutter in WebXR with ThreeJS 3 | version: 1.0.0+1 4 | environment: 5 | sdk: ">=2.1.0 <3.0.0" 6 | 7 | dependencies: 8 | flutter: 9 | sdk: flutter 10 | cupertino_icons: ^0.1.2 11 | threejs_facade: 12 | git: https://github.com/rodydavis/threejs-dart-facade 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | 18 | flutter: 19 | uses-material-design: true 20 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:flutter_webxr_threejs/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | flutter_webxr_threejs 18 | 19 | 73 | 74 | 75 | 76 | 102 | 105 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flutter_webxr_threejs", 3 | "short_name": "flutter_webxr_threejs", 4 | "start_url": ".", 5 | "display": "minimal-ui", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "An example of how to use Flutter in WebXR with ThreeJS", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /web/nyanlooped.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/web/nyanlooped.ogg -------------------------------------------------------------------------------- /web/nyanslow.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/FlutterWebXRThreeJS/9a5a760305782a77e7562746693fec456f13e566/web/nyanslow.ogg --------------------------------------------------------------------------------