├── .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
--------------------------------------------------------------------------------