106 | `;
107 | });
108 |
109 | return payload;
110 | };
111 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 BonsaiAI
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 | # Project Moab microsite
2 |
3 | Location for the Project Moab assets, tutorial, documentation and HTML
4 | content.
5 |
6 | ### Installation
7 | ```shell
8 | npm install
9 | ```
10 |
11 | ### Develop
12 |
13 | Starts a local server. This will start a 11ty server and auto reload on changes.
14 |
15 | ```shell
16 | npm run start
17 | ```
18 |
19 |
20 | ### Deploy
21 |
22 | Builds and commits to gh-pages branch.
23 |
24 | ```shell
25 | npm run deploy
26 | ```
27 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
40 |
41 |
--------------------------------------------------------------------------------
/_site/_data/encore.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | module.exports = function () {
4 | try {
5 | const data = fs.readFileSync('./build/entrypoints.json', 'utf8');
6 | const entrypoints = JSON.parse(data);
7 |
8 | return entrypoints.entrypoints;
9 | }catch (e) {
10 | console.log('looks like the files do not exists, waiting to let them be built');
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/_site/_includes/layouts/base.njk:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {%- for css in encore.app.css -%}
10 |
11 | {%- endfor -%}
12 |
13 |
20 |
21 | {{ title }}
22 |
23 |
24 | Learn to bridge the simulation-to-real-world gap by using Domain Randomization. By varying the AI's training environment, you will teach a brain that works better on real hardware.
25 |
Go beyond single-objective controllers by teaching an AI to balance the ball in the center while avoiding an obstacle.
30 |
31 | {% endfuji_block %}
32 |
33 |
--------------------------------------------------------------------------------
/_site/tutorials/1-balance.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layouts/page.njk
3 | title: "Project Moab - Tutorials 1: Train a Brain to Balance a Ball"
4 | class: md
5 | ---
6 |
7 | # Moab Tutorial 1: Train AI to Balance a Ball
8 |
9 | Teach an AI brain to balance a ball in the center of a plate using a custom simulator and sample code.
10 |
11 | **Total time to complete**: 45 minutes\
12 | **Active time**: 25 minutes\
13 | **Machine training time**: 20 minutes
14 |
15 | **Prerequisites**: To complete this tutorial, you must have a Bonsai workspace provisioned on Azure. If you do not have one, follow the [the account setup guide](https://docs.microsoft.com/en-us/bonsai/guides/account-setup).
16 |
17 | ## Outline
18 |
19 |
20 |
21 |
22 | - [Outline](#outline)
23 | - [Step 1: Define the problem](#step-1-define-the-problem)
24 | - [Step 2: Create a new brain](#step-2-create-a-new-brain)
25 | - [Step 3: Inspect the brain](#step-3-inspect-the-brain)
26 | - [Step 4: Understand goals](#step-4-understand-goals)
27 | - [Step 5. Train the brain](#step-5-train-the-brain)
28 | - [Step 6: Evaluate training progress](#step-6-evaluate-training-progress)
29 | - [Step 7: Assess the trained brain](#step-7-assess-the-trained-brain)
30 | - [Step 8: Export and Deploy](#step-8-export-and-deploy)
31 | - [Next steps](#next-steps)
32 | - [Feedback and discussion](#feedback-and-discussion)
33 |
34 |
35 |
36 |
37 |
38 | ## Step 1: Define the problem
39 |
40 | Imagine you are holding a plate and trying to keep a ball balanced in the center.
41 |
42 | How would you do it?
43 |
44 | First, you observe the ball:
45 |
46 | - You could track the movement visually.
47 | - You could track the vibrations in the plate by feel.
48 | - You could track the rolling sound.
49 |
50 | In observing the ball, you intuitively determine its **current location and speed**.
51 |
52 | Next, you act on the gathered information:
53 |
54 | - If the ball is already in the center, hold the plate flat to keep it there.
55 | - If the ball moves away from the center, adjust the plate angle to move the ball back.
56 |
57 | In adjusting the plate angle, you alter its **pitch and roll**.
58 |
59 | ### Ball Balance using the Moab Device
60 |
61 | 
62 |
63 | Microsoft Project Moab is a fully integrated system for users of all levels to learn and explore building autonomous intelligent controls using reinforcement learning through Project Bonsai's Machine Teaching platform. The device (shown in the previous image) has three arms powered by servo motors. These arms work in tandem to control the angle of the transparent plate to keep the ball balanced.
64 |
65 |
66 |
67 |
68 | The Moab device tracks and maps the the ball movement onto a standard 2D coordinate system. Looking at the front the of the device, the **x-axis** runs left-to-right, and the **y-axis** runs front-to-back, with the plate center at location (0, 0), and a radius of r.
69 |
70 | The same coordinate system is also used to define the two different tilt angles. Pitch is the plate angle about the x-axis, roll is the plate angle about the y-axis. A perfectly level plate would have pitch and roll of (0, 0).
71 |
72 | The trained AI must learn how to adjust the plate pitch and roll to balance a ball using the following objectives:
73 |
74 | 1. The ball position (x, y) will reach the plate center at (0, 0) and stay there.
75 | 2. The ball position will not get near the plate edge at ( | (x, y) - (0, 0) | << r).
76 |
77 | Now that you have identified the problem and defined the objectives, use machine teaching to train an AI to balance a ball.
78 |
79 |
80 |
81 | ## Step 2: Create a new brain
82 |
83 |
84 |
85 | To start a new Moab brain:
86 |
87 | 1. Create an account or sign into Bonsai.
88 | 2. Click the **Moab** icon in the **Getting started** panel, or **Create Brain** and **Moab demo**, as in the previous illustration.
89 | 3. Name your new brain (e.g., "Moab Tutorial 1").
90 | 4. Click **Create**
91 |
92 |
93 |
94 | ## Step 3: Inspect the brain
95 |
96 | After creating the Moab sample brain and simulator sample, Bonsai automatically opens the teaching interface, which is prepopulated with everything you need to get started.
97 |
98 |
99 |
100 | The teaching interface has three areas, as in the previous illustration:
101 |
102 | - The **Navigation sidebar** lists all your brains and simulators.
103 | - The **Coding panel** is your Inkling code editor. Inkling is a machine teaching proprietary language, designed to focus on what you want to teach while handling the AI details for you.
104 | - The **Graphing panel** displays an interactive, graphical representation of the observable state, concept, and `SimAction` currently defined in the coding panel.
105 |
106 | ### Inspect the state node: ObservableState
107 |
108 |
109 |
110 | Click the `ObservableState`node to jump to the relevant part of your Inkling code, as in the previous illustration.
111 |
112 | `ObservableState` defines what information the brain is sent during every simulation iteration. For your ball balancing problem, the Moab device tracks the ball position and velocity. So, your simulation `ObservableState` is:
113 |
114 | - `ball_x`, `ball_y`: the (x, y) ball position.
115 | - `ball_vel_x`, `ball_vel_y`: the x and y ball velocity components.
116 |
117 | ```
118 | # State received from the simulator after each iteration
119 | type ObservableState {
120 | # Ball X,Y position
121 | ball_x: number<-RadiusOfPlate .. RadiusOfPlate>,
122 | ball_y: number<-RadiusOfPlate .. RadiusOfPlate>,
123 |
124 | # Ball X,Y velocity
125 | ball_vel_x: number<-MaxVelocity .. MaxVelocity>,
126 | ball_vel_y: number<-MaxVelocity .. MaxVelocity>,
127 | }
128 | ```
129 |
130 | Each state has an associated expected range. In the previous code snippet, the `ball_x` and `ball_y` locations are bounded by the plate radius. If provided, ranges can reduce AI training time.
131 |
132 | ### Inspect the actions node: SimAction
133 |
134 |
135 |
136 | Click on the `SimAction` node to jump to the next part of your Inkling code.
137 |
138 | `SimAction` defines the ways that the brain interacts with the simulated environment. In your simulation, this is reflected by the following variables:
139 |
140 | - `input_pitch`: a value that sets the plate angle along the X axis
141 | - -1 means tilt all the way forwards (away from the joystick), +1 means tilt all the way backwards (toward the joystick)
142 | - `input_roll`: a value that sets the target plate angle along the Y axis
143 | - -1 means tilt all the way to the left, +1 means tilt all the way to the right
144 |
145 | As highlighted before, the Moab device tilts the plate with two orthogonal angles (`SimAction`). An onboard algorithm translates this action to the three servo-powered arms, achieving the desired tilt.
146 |
147 | ```
148 | # Action provided as output by policy and sent as
149 | # input to the simulator
150 | type SimAction {
151 | # Range -1 to 1 is a scaled value that represents
152 | # the full plate rotation range supported by the hardware.
153 | input_pitch: number<-1 .. 1>, # rotate about x-axis
154 | input_roll: number<-1 .. 1>, # rotate about y-axis
155 | }
156 | ```
157 |
158 | ### Inspect the concept node: MoveToCenter
159 |
160 | Click on the `MoveToCenter`concept node to define what the AI should learn, as in the following example:
161 |
162 | A `goal` describes what you want the brain to learn using one or more objectives (previously defined), as in the following example:
163 |
164 | ```
165 | # Define a concept graph with a single concept
166 | graph (input: ObservableState) {
167 | concept MoveToCenter(input): SimAction {
168 | curriculum {
169 | # The source of training for this concept is a simulator that
170 | # - can be configured for each episode using fields defined in SimConfig,
171 | # - accepts per-iteration actions defined in SimAction, and
172 | # - outputs states with the fields defined in SimState.
173 | source simulator (Action: SimAction, Config: SimConfig): ObservableState {
174 | }
175 | ...
176 | ```
177 |
178 | A `concept` defines what the AI needs to learn and the `curriculum` is how it learns. Your `MoveToCenter`concept will receive simulator states and respond with actions.
179 |
180 |
181 |
182 | ## Step 4: Understand goals
183 |
184 | We previously defined two objectives for our brain:
185 |
186 | - The ball position will not get near the plate edge at ( | (x, y) - (0, 0) | << r).
187 | - The ball position (x, y) will reach the plate center at (0, 0) and stay there.
188 |
189 | A `goal` describes what you want the brain to learn using one or more objectives, as in the following example:
190 |
191 | ```
192 | # The training goal has two objectives:
193 | # - don't let the ball fall off the plate
194 | # - drive the ball to the center of the plate
195 | goal (State: ObservableState) {
196 |
197 | avoid `Fall Off Plate`:
198 | Math.Hypot(State.ball_x, State.ball_y) in Goal.RangeAbove(RadiusOfPlate * 0.8)
199 |
200 | drive `Center Of Plate`:
201 | [State.ball_x, State.ball_y] in Goal.Sphere([0, 0], CloseEnough)
202 | }
203 | ```
204 |
205 | As the brain trains, it attempts to simultaneously meet all the defined objectives during each episode.
206 |
207 | Available goal objectives include:
208 |
209 | - `avoid`: Avoid a defined region.
210 | - `drive`: Get to a target as quickly as possible and stay in that place.
211 | - `reach`: Get to a target as quickly as possible.
212 |
213 | For your objectives, use `avoid` and `drive`, as follows:
214 |
215 | ### Objective: Avoid falling off the plate
216 |
217 | To teach the brain to keep the ball on the plate, use `avoid` to define an objective called `Fall Off Plate`, as in the following code snippet:
218 |
219 | ```
220 | avoid `Fall Off Plate`:
221 | Math.Hypot(State.ball_x, State.ball_y) in Goal.RangeAbove(RadiusOfPlate * 0.8)
222 | ```
223 |
224 | An `avoid` objective asks the brain to learn to avoid a certain region of states. Your objective states that the ball's distance from the center must not reach values above 80% of the plate radius. This will teach the brain to keep the ball on the plate.
225 |
226 | ### Objective: Move the ball to the center of the plate
227 |
228 | To teach the brain to move the ball to a specific spot and keep it there, use `drive` to define a objective called `Center Of Plate`, as in the following code snippet:
229 |
230 | ```
231 | drive `Center Of Plate`:
232 | [State.ball_x, State.ball_y] in Goal.Sphere([0, 0], CloseEnough)
233 | ```
234 |
235 | A `drive` objective asks the brain to learn to reach to a target as soon as possible and stay there. In this case, the target is for the ball's X and Y coordinates (`state.ball_x` and `state.ball_y`) to stay within `CloseEnough` radial distance from the plate center.
236 |
237 |
238 |
239 | ## Step 5. Train the brain
240 |
241 | After defining the brain objectives, Click the **Train** button to start training and open the Train UI, as seen in the following screenshot:
242 |
243 |
244 |
245 | When training starts, Bonsai launches multiple Moab simulator instances in the cloud. The training progress is reflected in several UI sections, as seen in the following screenshot:
246 |
247 |
248 |
249 | ### Section 1: Training performance plot
250 |
251 | Start with the chart at the top of the data panel that displays the **performance plot**, as seen in the following screenshot:
252 |
253 |
254 |
255 | This shows the average performance of the brain from test episodes that are regularly run during training. (A test episode evaluates the brain's performance without the exploratory actions used during training to help the brain learn.)
256 |
257 | Next, inspect the goal satisfaction plots. Goal satisfaction plots display the brains' achievement progress for each objective. For example, 100% Goal Satisfaction for `Fall Off Plate` indicates that the brain has learned to consistently keep the ball on the plate. The overall **Goal Satisfaction** line is the average goal satisfactions across all the objectives. Select several other performance metrics using the Y-axis selector.
258 |
259 | As it trains, the brain improves at accomplishing the goals you defined. The goal satisfaction values should eventually reach close to 100%.
260 |
261 | ### Section 2: Simulator node
262 |
263 | The teaching graph has a new **Simulator** node in the graphing panel, as seen in the following screenshot:
264 |
265 |
266 |
267 | The simulator node displays the following:
268 |
269 | - the number of simulation iterations running in parallel.
270 | - the overall iterations per second.
271 |
272 | During training, the concept node displays the latest goal satisfaction.
273 |
274 | ### Section 3: Moab Device Visualization
275 |
276 | There is a live visualization of the Moab simulator below the performance plot, as seen in the following screenshot:
277 |
278 |
279 |
280 | In addition to the 3D ball and hardware, the visualization displays the following:
281 |
282 | - The ball velocity (the blue arrow projected onto the plate)
283 | - The estimated ball position (blue circle projected on to the plate under the ball).
284 |
285 | Click and drag to rotate the visualization view angle.
286 |
287 | Below the visualization is an interactive graph that plots training values, as seen in the following screenshot:
288 |
289 |
290 |
291 | Click `ball_x` and `ball_y` to display the ball X and Y coordinates. The vertical dashed lines show the stop and start of new episodes.
292 |
293 | As the brain learns to keep the ball from falling off the plate, each episode will get longer. As the brain learns to center the ball, `ball_x` and `ball_y` will reach zero every episode.
294 |
295 | While you wait for the brain to train, try charting other values.
296 |
297 |
298 |
299 | ## Step 6: Evaluate training progress
300 |
301 | ### When should we stop training?
302 |
303 | The **Goal Satisfaction %** trends upwards during the first 100k – 200k iterations. Afterwards, the various performance lines will converge and flatten. After training for an hour or so, you should see a plot similar to the following screenshot:
304 |
305 |
306 |
307 | Here, performance has reached a peak level and additional training time does not seem to yield any improvement.
308 |
309 | **Training can be stopped when you notice that the Goal Satisfaction has not made any meaningful progress, which should occur before 500k iterations.** Hitting the Train button afterwards will resume training.
310 |
311 | Congratulations! You have successfully trained a brain to balance the ball!
312 |
313 |
314 |
315 | ## Step 7: Assess the trained brain
316 |
317 | Click the **Start Assessment** button on the Train page, and the following sub-window should appear.
318 |
319 |
320 |
321 | After the simulator starts, the visualizer and streaming charts from training are displayed. In assessment mode, the brain is tested using the same random scenarios defined in the Inkling lesson.
322 |
323 |
324 |
325 |
326 |
327 | ## Step 8: Export and Deploy
328 |
329 | Here is a video of a trained brain from this tutorial, deployed on the Moab hardware:
330 |
331 |
332 |
333 | Once Moab kits ship, look here for instructions on deploying the trained brain onto your bot.
334 |
335 |
336 | ## Next steps
337 |
338 | Congratulations! You trained a brain that can balance a ball on a plate, and can be deployed on real hardware. In [Tutorial 2](../2-robustness/index.html), you will learn how to use domain randomization to make the deployed brain more robust to differences between simulation and real life.
339 |
340 |
341 | ## Feedback and discussion
342 |
343 | Discuss this tutorial and ask questions in the [Bonsai community forums](https://aka.ms/as/forums).
344 |
345 | We would appreciate your feedback! [Submit feedback and product feature requests](https://aka.ms/as/productfeedback).
--------------------------------------------------------------------------------
/_site/tutorials/2-robustness.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layouts/page.njk
3 | title: "Project Moab - Tutorial 2: Robust Balancing via Domain Randomization"
4 | class: md
5 | ---
6 |
7 | # Moab Tutorial 2: Robust Balancing via Domain Randomization
8 |
9 | In Tutorial 1, you taught an AI to balance a ball on a plate. If you deployed it on real hardware, you observed that it works, but does not react very quickly, and it's easy to push the ball off the plate. In this tutorial, you will teach an AI to balance a ball more robustly.
10 |
11 | **Total time to complete**: 60 minutes\
12 | **Active time**: 20 minutes\
13 | **Machine training time**: 40 minutes
14 |
15 | **Prerequisites**: To complete this tutorial, you must have a Bonsai workspace provisioned on Azure. If you do not have one, follow the [the account setup guide](https://docs.microsoft.com/en-us/bonsai/guides/account-setup).
16 |
17 | ## Outline
18 |
19 | - [Step 1: Intro to Domain Randomization](#intro)
20 | - [Step 2: Choose Physical Parameters to Vary](#vary)
21 | - [Step 3: Start a New Brain](#new)
22 | - [Step 4: Using Lessons to Implement DR](#dr)
23 | - [Step 5. Implement New Lesson](#newlesson)
24 | - [Step 6. Experimentation Tips](#experimentation)
25 | - [Step 7: Assess Performance of the Trained Brain](#prediction)
26 | - [Step 8 (optional): Export and Deploy](#deploy)
27 | - [Next steps](#nextsteps)
28 |
29 |
30 |
31 | ## Step 1: Intro to Domain Randomization
32 |
33 | Training an AI in simulation is much easier and faster than training on real hardware: there are no safety concerns, and no need to build, maintain, and continually reset physical training environments. Many simulators can be run in parallel at low cost, making training a much faster process. However, there is a risk of training in simulation: a simulation almost never captures every aspect of the real world, and there is a tradeoff between simulator fidelity and its cost and simulation speed. If the AI learns to take advantage of imperfections in the simulation, it can work very well in simulation and poorly when deployed. This is often called the sim-to-real gap.
34 |
35 | This tutorial will use a technique called Domain Randomization (DR) to address the sim-to-real gap. DR works by introducing extra variability into the simulated environment during AI training. By doing so, the AI must learn a strategy that works in scenarios with different properties. This increases the chance that the trained AI will perform well in the real-world environment.
36 |
37 | The following steps will illustrate DR on Bonsai:
38 |
39 | 1. Select physical parameters that are useful for DR
40 | 2. Learn how to specify DR in Inkling by reviewing sample code.
41 | 3. Use DR to train Moab to be more robust when balancing a ball
42 |
43 |
44 |
45 |
46 | ## Step 2: Choose Physical Parameters to Vary
47 |
48 | ### Varying initial conditions
49 | #
50 | When you place a ball on Moab, the following conditions can vary:
51 | - plate position
52 | - initial velocity
53 | - initial plate tilt.
54 |
55 | The Moab simulator can model these initial conditions using the parameters in the following table:
56 |
57 | | **Parameter Name** | **Units** | **Description** |
58 | | --- | --- | --- |
59 | | initial_pitch | Scalar between -1, +1 | Normalized initial pitch angle of plate |
60 | | initial_roll | Scalar between -1, +1 | Normalized initial roll angle of plate |
61 | | initial_x | Meters | Initial X position of ball |
62 | | initial_y | Meters | Initial Y position of ball |
63 | | initial_vel_x | Meters/Sec | Initial X velocity of ball |
64 | | initial_vel_y | Meters/Sec | Initial Y velocity of ball |
65 |
66 | ### Varying environmental properties
67 |
68 | By default, the Moab simulator simulates a fixed size and weight ping-pong ball. The ball radius(`ball_radius`) and shell thickness (`ball_shell`) can be changed to alter the ball dynamics. The ratio between shell thickness and ball radius defines the ball thickness. The thicker the ball, the faster the acceleration. The following table details these simulator parameters:
69 |
70 | | **Parameter Name** | **Units** | **Description** |
71 | | --- | --- | --- |
72 | | ball_radius | Meters | Radius of the ball (0.02 for Ping-Pong ball) |
73 | | ball_shell | Meters | Shell thickness of the ball (0.0002 for Ping-Pong ball) |
74 |
75 |
76 |
77 | ## Step 3: Start a New Brain
78 |
79 |
80 |
81 | Start a new brain for this tutorial.
82 |
83 | To start a new Moab brain:
84 |
85 | 1. Create an account or sign into Bonsai.
86 | 2. Click the **Moab** icon in the **Getting started** panel, or **Create Brain** and **Moab demo**
87 | 3. Name your new brain (e.g., "Moab Tutorial 2").
88 | 4. Click **Create**
89 |
90 |
91 |
92 | ## Step 4: Using Lessons to Implement DR
93 |
94 | To implement DR, configure the simulated environment differently for each training episode. You do this in Inkling using a lesson. A lesson describes the set of scenarios the simulator can be configured with at the beginning of each episode. You can vary initial conditions (such as positions and velocities), and environmental properties (such as object sizes, sensor accuracies, hardware properties).
95 |
96 | In the starting Moab Inkling, review the lesson in the `MoveToCenter` concept:
97 |
98 | Click on the concept node in the right panel to navigate to the Inkling code section defining the `MoveToCenter` concept.
99 |
100 |
101 |
102 | The cursor should automatically scroll and highlight the following Inkling declaration:
103 |
104 | ```
105 | graph (input: ObservableState) {
106 | concept MoveToCenter(input): SimAction {
107 | curriculum {
108 | source MoabSim
109 | ...
110 | ...
111 | }
112 | ...
113 | ...
114 | ```
115 |
116 | Teaching the AI the `MoveToCenter` concept requires defining a goal and one or more lessons to teach that goal, as in the following code example:
117 |
118 | ```
119 | lesson `Randomize Start` {
120 | # Specify the configuration parameters that should be varied
121 | # from one episode to the next during this lesson.
122 | scenario {
123 | initial_x: number<-RadiusOfPlate * 0.5 .. RadiusOfPlate * 0.5>,
124 | initial_y: number<-RadiusOfPlate * 0.5 .. RadiusOfPlate * 0.5>,
125 | initial_vel_x: number<-0.02 .. 0.02>,
126 | initial_vel_y: number<-0.02 .. 0.02>,
127 | initial_pitch: number<-0.2 .. 0.2>,
128 | initial_roll: number<-0.2 .. 0.2>,
129 | }
130 | }
131 | ```
132 |
133 | Each scenario parameter is selected randomly at the start of each training episode. The previous example configuration initializes the ball position in the square with x and y between –0.5*r and 0.5*r, where r is the plate radius. Initial velocity is up to 0.02 m/s in each direction. This is quite slow. The initial roll and pitch go up to 20% of the maximum tilt (22 degrees).
134 |
135 |
136 |
137 | ## Step 5. Implement New Lesson
138 |
139 | Increase the difficulty of the lesson by increasing the ranges of existing scenario parameters, and domain randomizing the ball parameters.
140 |
141 | To add DR for the ball, you will perform the following steps:
142 | - Add constants describing the ping pong ball
143 | - Hook up additional configuration parameters for the simulator
144 | - add the new parameters to the lesson to and increase the ranges on the others.
145 |
146 | ### Increase parameter ranges
147 |
148 | Increase the initial position up to 0.6 times the plate radius, and initial velocity up to 0.4 * MaxVelocity, as in the following code:
149 |
150 | ```
151 | scenario {
152 | initial_x: number<-RadiusOfPlate * 0.6 .. RadiusOfPlate * 0.6>,
153 | initial_y: number<-RadiusOfPlate * 0.6 .. RadiusOfPlate * 0.6>,
154 | initial_vel_x: number<-MaxVelocity * 0.4 .. MaxVelocity * 0.4>,
155 | initial_vel_y: number<-MaxVelocity * 0.4 .. MaxVelocity * 0.4>,
156 | initial_pitch: number<-0.2 .. 0.2>,
157 | initial_roll: number<-0.2 .. 0.2>,
158 | }
159 | ```
160 |
161 | We could increase the pitch and roll limits as well. The initial angle turns out not to matter much because the Moab can change pitch and roll very quickly.
162 |
163 | ### Add Constants
164 |
165 | At the top of your Inkling, add the `PingPongRadius` and `PingPongShell` constants between the `RadiusOfPlate` and `MaxVelocity` constants using the following code:
166 |
167 | ```
168 | # Ping-Pong ball constants
169 | const PingPongRadius = 0.020 # m
170 | const PingPongShell = 0.0002 # m
171 | ...
172 | ```
173 |
174 | ### Adding More Parameters in Simulator Configuration
175 |
176 | Add the `ball_radius` and `ball_shell` parameters to the bottom of the `SimConfig` Inkling section, using the following code:
177 |
178 | ```
179 | ball_radius: number, # Radius of the ball in (m)
180 | ball_shell: number, # Shell thickness of ball in (m), shell>0, shell<=radius
181 | ```
182 |
183 | Any simulator parameters that aren't included in `SimConfig` are assigned a default value by the simulator.
184 |
185 | > **Note:** You can see the full list of available state, action, and configuration variables for a simulator by opening the `Moab` simulator in the **Navigation Side Panel**.
186 |
187 | ### Domain Randomize Ball Radius and Ball Shell
188 |
189 | Use the new `SimConfig` parameters in a lesson. Add `ball_radius` and `ball_shell` to the bottom of the `Randomize Start` lesson with the following lines of code:
190 |
191 | ```
192 | ball_radius: number,
193 | ball_shell: number,
194 | ```
195 | By adding this change, the AI will strive to achieve the same goal but uses a ball with a randomly selected radius and shell thickness (between 80% and 120%) for every new episode.
196 |
197 | *Note:* if you had any trouble completing the above steps, please tell us what went wrong in the [Bonsai community forums](https://aka.ms/as/forums), and copy the full Inkling from the [github repo](https://github.com/microsoft/moabsim-py/blob/main/moab_tutorial_2.ink) to continue.
198 |
199 | To start the experiment, click **Train**. The Moab simulator will start automatically based on the `package` statement in Inkling.
200 |
201 |
202 |
203 | ## Step 6. Experimentation Tips
204 |
205 | Successfully developing a trained AI often requires multiple rounds of experimentation. Some experiments may be successful, reach a dead end, or inspire completely different courses of investigation. The Bonsai interface has features to assist your experimentation.
206 |
207 | ### Training Multiple Different Brains in Parallel
208 |
209 | The Navigation Panel on the left shows all brains in your workspace, as in the following illustration:
210 |
211 |
212 |
213 |
214 | > **Note:** If you have an Azure free account, the quota restrictions for Azure Container Instances (used to run the simulators) will prevent training more than one brain a time. Upgrade to a pay-as-you-go account or use an organizational account with higher quotas to take full advantage of Bonsai's experimentation features.
215 |
216 | To train multiple brains, select an existing brain and then click **Train** to start training. Each brain will contain the latest corresponding Inkling code. As brains train, the Brains Panel will also display the latest performance.
217 |
218 | Rename your brain or add an experiment description by right clicking on a brain and selecting **Info**, as in the following illustrations:
219 |
220 |
221 |
222 |
223 |
224 |
225 | ### Versioning
226 |
227 | The Bonsai interface enables you to keep track of different brain versions. If the Inkling code is changed in a way that requires a reset, a training start will automatically generate a new brain version.
228 |
229 |
230 |
231 |
232 | Write per-version notes or copy a brain version by right clicking on it.
233 |
234 |
235 |
236 |
237 |
238 |
239 | ## Step 7: Assess Performance of the Trained Brain
240 |
241 | Once training is stopped, run tests on the trained AI.
242 |
243 | Click the **Start Assessment** button on the **Train** tab, and the following sub-window will appear after a minute or so.
244 |
245 |
246 |
247 | In this mode, the trained brain is tested continuously, initializing each episode using the domain randomization defined in Inkling. Monitor performance using the Moab visualizer and line charts.
248 |
249 |
250 |
251 | ## Step 8 (optional): Export and Deploy
252 |
253 | The following video shows a trained brain from this tutorial:
254 |
255 |
256 |
257 | Once Moab kits ship, look here for instructions on deploying the trained brain onto your bot.
258 |
259 |
260 |
261 | ## Next steps
262 |
263 | Congratulations! You trained a brain that can robustly balance a ball on real hardware. In [Tutorial 3](../3-fixed-obstacle/index.html), you will learn how to use additional goals to make the ball balance while avoiding an obstacle.
264 |
265 | ## Feedback and discussion
266 |
267 | Discuss this tutorial and ask questions in the [Bonsai community forums](https://aka.ms/as/forums).
268 |
269 | We would appreciate your feedback! [Submit feedback and product feature requests](https://aka.ms/as/productfeedback).
--------------------------------------------------------------------------------
/_site/tutorials/3-fixed-obstacle.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layouts/page.njk
3 | title: "Project Moab - Tutorial 3: Balance with a Fixed Obstacle"
4 | class: md
5 | ---
6 |
7 | # Moab Tutorial 3: Balance with a Fixed Obstacle
8 |
9 | Teach an AI to balance a ball in the center of a plate with Bonsai, a predefined simulator, and sample code.
10 |
11 | **Total time to complete**: 3 hours\
12 | **Active time**: 25 minutes\
13 | **Machine training time**: 2.5 hours
14 |
15 | **Prerequisites**: To complete this tutorial, you must have a Bonsai workspace provisioned on Azure. If you do not have one, follow the [the account setup guide](https://docs.microsoft.com/en-us/bonsai/guides/account-setup).
16 |
17 | ## Outline
18 |
19 | - [Step 1: Define the problem](#problem)
20 | - [Step 2: Start a new brain](#start)
21 | - [Step 3: Define hole location](#hole)
22 | - [Step 4. Adding additional simulator states](#states)
23 | - [Step 5. Add a new objective](#objective)
24 | - [Step 6: Train](#train)
25 | - [Step 7: Running predictions on trained brain](#predictions)
26 | - [Step 8 (optional): Export and deploy](#export)
27 | - [Next steps](#nextsteps)
28 | - [Give us Feedback](#feedback)
29 |
30 |
31 | ## Step 1: Define the problem
32 |
33 | Imagine that once you completed training the Moab device to balance a ball, someone decides to swap the plate you are holding with a new plate and poses a new challenge. The new plate is the same size but contains a hole. The new challenge is to balance the ball to the center but keep the ball away from landing in the hole, and a solution needs to be developed as soon as possible.
34 |
35 | How does this added complexity change your approach? How would you translate a new strategy and teach a machine to do this?
36 |
37 | The machine teaching tools on the Bonsai platform are designed to tackle situations like this. In this tutorial, you will learn how to naturally and efficiently translate this new requirement and solve this more complex problem.
38 |
39 |
40 | ## Step 2: Start a new brain
41 |
42 |
43 |
44 | To build your brain:
45 |
46 | 1. [Sign into the Bonsai UI](https://preview.bons.ai).
47 | 1. Select **Moab** from the list of demo brains from the **Getting Started**
48 | dialog.
49 | 1. Name your new brain (for example, "Moab Tutorial 3").
50 | 1. Click **Create Brain** to load the sample brain and simulator.
51 | 1. Start from the [Inkling for tutorial 2](https://github.com/microsoft/moabsim-py/blob/main/moab_tutorial_2.ink). Copy and paste it into the Inkling editor, replacing the default Inkling.
52 |
53 |
54 | ## Step 3: Define hole location
55 |
56 | ### Add obstacle configuration
57 |
58 | To start, simulate the scenario. The Moab simulator can model one obstacle, represented as a circular region on the plate. These are the Moab simulator parameters used to set up obstacles:
59 |
60 | |**Parameter Name** |**Units** |**Description** |
61 | |----------------|------|-------------|
62 | |obstacle_radius |Meters|Radius of the circular obstacle region|
63 | |obstacle_x |Meters|Center X location of circle region|
64 | |obstacle_y |Meters|Center Y location of circle region|
65 |
66 | Example 1: Values to create an avoid region at the center of the plate with radius of 2cm:
67 |
68 | - obstacle_radius = 0.02
69 | - obstacle_x = 0.0
70 | - obstacle_y = 0.0
71 |
72 | Example 2: Values to create an avoid region centered 5 cm directly above the center of the plate with radius of 1 cm:
73 |
74 | - obstacle_radius = 0.01
75 | - obstacle_x = 0.0
76 | - obstacle_y = 0.05
77 |
78 | Example 3: Values to create an avoid region centered 3 cm directly above the center of the plate with radius of 3 cm:
79 |
80 | - obstacle_radius = 0.03
81 | - obstacle_x = -0.03
82 | - obstacle_y = 0.0
83 |
84 | Scroll to `SimConfig`, then add `obstacle_radius`, `obstacle_x`, and `obstacle_y` to the end of `SimConfig` as in the following code:
85 |
86 | ```
87 | # Obstacle information
88 | obstacle_radius: number,
89 | obstacle_x: number,
90 | obstacle_y: number,
91 | ```
92 |
93 | ### Pick a location for the obstacle
94 |
95 | Use these new `SimConfig` parameters to configure the obstacle position and size. Put an obstacle with radius 1cm at (4cm, 4cm) and define a 1cm “cushion” -- how far from the obstacle you want the ball to stay. At the top of the Inkling file, define constants for these (remember that distances are in meters.)
96 |
97 | ```
98 | # Obstacle definitions
99 | const ObstacleRadius = 0.01
100 | const ObstacleLocationX = 0.04
101 | const ObstacleLocationY = 0.04
102 |
103 | # How far to stay from the obstacle
104 | const Cushion = 0.01
105 | ```
106 |
107 | ### Add obstacle config to the scenario
108 |
109 | At the end of the **Randomize Start** lesson, add the following lines to set the obstacle position and size. Note that these are being set to constant values, so will not be randomized during training.
110 |
111 | ```
112 | # Configure obstacle parameters
113 | obstacle_radius: ObstacleRadius,
114 | obstacle_x: ObstacleLocationX,
115 | obstacle_y: ObstacleLocationY,
116 | ```
117 |
118 | Note that for some specified scenarios, our specified goal will be impossible to achieve. Since each variable in the scenario is randomized independently, it is possible that the ball will start on top of the obstacle or headed quickly toward it. These should not impede training—the AI will fail in impossible-to-satisfy scenarios and keep trying others. This will affect the achievable success rate – even a perfect brain will not be able to succeed 100% of the time.
119 |
120 |
121 | ## Step 4. Adding additional simulator states
122 |
123 | Because the obstacle is fixed in this tutorial, the brain does not need to be passed information about the obstacle as part of the `ObservableState`. However, the brain does need the obstacle location during training. To support this, we will define a new type: `SimState`, which will include the distance and direction to the obstacle. We will use this in our goal definition to train the brain.
124 |
125 | The Moab simulator outputs the direction and distance from ball to obstacle. The obstacle distance is measured between the edge of the ball and the edge of the obstacle. Values less than 0 mean that the ball has hit the obstacle.
126 | To reveal these new states to the AI brain during training, In Inkling, copy `ObservableState` and rename it `SimState`, as in the following code:
127 |
128 | ```
129 | type SimState {
130 | # Ball X,Y position, noise applied
131 | ball_x: number<-RadiusOfPlate .. RadiusOfPlate>,
132 | ball_y: number<-RadiusOfPlate .. RadiusOfPlate>,
133 |
134 | # Ball X,Y velocity, noise applied
135 | ball_vel_x: number<-MaxVelocity .. MaxVelocity>,
136 | ball_vel_y: number<-MaxVelocity .. MaxVelocity>,
137 | }
138 | ```
139 |
140 | Next, add parameters `obstacle_direction` and `obstacle_distance` to the Inkling, as in the following code:
141 |
142 | ```
143 | type SimState {
144 | ...
145 |
146 | # Obstacle data
147 | obstacle_direction: number<-Math.Pi .. Math.Pi>,
148 | obstacle_distance: number<-2.0*RadiusOfPlate .. 2.0*RadiusOfPlate>,
149 | }
150 | ```
151 |
152 | Next, tell the system that the simulator will be sending us values of type `SimState`. Change `ObservableState` to `SimState` in the `source simulator` line in the `MoveToCenter` concept:
153 |
154 | ```
155 | source simulator (Action: SimAction, Config: SimConfig): SimState {
156 | }
157 | ```
158 |
159 | Because `ObservableState` is a subset of `SimState`, the brain will automatically pass only the observable values to the policy, and the final trained brain will only require `ObservableState` values to make its decisions. The goal definition can use the full `SimState`, so change `ObservableState` to `SimState` in the `goal` statement, as in the following code:
160 |
161 | ```
162 | goal (State: SimState) {
163 | ...
164 | ```
165 |
166 |
167 | ## Step 5. Add a new objective
168 |
169 | Next, tell the AI that it should avoid the obstacle as it attempts to balance the ball. Add the following code after the `drive CenterOfPlate:` objective at the end of the `goal` statement inside the `curriculum`:
170 |
171 | ```
172 | avoid HitObstacle: State.obstacle_distance in Goal.RangeBelow(Cushion)
173 | ```
174 |
175 | That’s it! Now the AI will learn to avoid hitting the obstacle if it can.
176 |
177 | *Note:* if you had any trouble completing the above steps, please tell us what went wrong in the [Bonsai community forums](https://aka.ms/as/forums), and copy the full Inkling from the [github repo](https://github.com/microsoft/moabsim-py/blob/main/moab_tutorial_3.ink) to continue.
178 |
179 |
180 |
181 | ## Step 6: Train
182 |
183 |
184 | > **NOTE: Running simulations consumes Azure resources. Following the tutorial as
185 | > written will charge your Azure subscription approximately 1.00 USD. Repeated
186 | > training or running the training longer than recommended will result in
187 | > additional cost.**
188 |
189 |
190 |
191 | To start an experiment, click **Train**. The system will prompt you to select a simulator. Pick Moab.
192 |
193 |
194 |
195 | Note: To have the Moab simulator start without prompting, you can add a package statement to the simulator statement in Inkling, as in the following code:
196 |
197 | ```
198 | source simulator (Action: SimAction, Config: SimConfig): SimState {
199 | # Automatically launch the simulator with this
200 | # registered package name.
201 | package "Moab"
202 | }
203 | ```
204 |
205 | The system will automatically start simulators and start training. This problem is more complex than simply balancing, and may take 30 minutes or more to train. You should see a goal satisfaction plot similar to this:
206 |
207 |
208 |
209 |
210 | ## Step 7: Running predictions on trained brain
211 |
212 | Once training is stopped, you can run tests on the trained AI.
213 |
214 | Click the **Start Assessment** button on the **Train** page, and the following sub-window should appear:
215 |
216 |
217 |
218 | In this mode, the trained brain is tested continuously, with each episode initialized using the domain randomization defined in Inkling. You can watch the Moab visualizer and line charts.
219 |
220 |
221 | ## Step 8 (optional): Export and deploy
222 |
223 | Here is a video of a trained brain from this tutorial:
224 |
225 |
226 |
227 | Once Moab kits ship, look here for instructions on deploying the trained brain onto your bot.
228 |
229 |
230 |
231 | ## Next steps
232 |
233 | Congratulations! You trained a brain that can robustly balance a ball on real hardware, while avoiding an obstacle. Look for more tutorials coming soon.
234 |
235 | In the meantime, try exploring on your own: can you train a brain to avoid obstacles at different locations?
236 |
237 |
238 |
239 | # Give us feedback
240 |
241 | We're just opening the platform to the public, and would really appreciate your feedback to help us improve!
242 |
243 | * Fill out the feedback survey!
244 | * [Submit feedback and product feature requests](https://aka.ms/as/productfeedback).
245 | * Discuss this tutorial and ask questions in the [Bonsai community forums](https://aka.ms/as/forums).
246 |
247 |
248 | Thank you!
--------------------------------------------------------------------------------
/img/Hero 1_04-29-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/Hero 1_04-29-20.png
--------------------------------------------------------------------------------
/img/Hero 2_04-29-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/Hero 2_04-29-20.png
--------------------------------------------------------------------------------
/img/Packaging 1_04-29-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/Packaging 1_04-29-20.png
--------------------------------------------------------------------------------
/img/background-dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/background-video.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/background-video.mp4
--------------------------------------------------------------------------------
/img/balance-plate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/balance-plate.png
--------------------------------------------------------------------------------
/img/control-arms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/control-arms.png
--------------------------------------------------------------------------------
/img/documents-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/documents-home.png
--------------------------------------------------------------------------------
/img/fresh-video-cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/fresh-video-cover.png
--------------------------------------------------------------------------------
/img/github-repo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/github-repo.png
--------------------------------------------------------------------------------
/img/icons/close.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/img/icons/doc.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/img/icons/download.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/img/icons/expand.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/img/icons/external.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/img/icons/github.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/img/icons/internal.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/img/icons/play.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/img/icons/tutorial.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/img/icons/video.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/img/servo-motors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/servo-motors.png
--------------------------------------------------------------------------------
/img/tutorials-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials-home.png
--------------------------------------------------------------------------------
/img/tutorials/1/bonsai-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/bonsai-home.png
--------------------------------------------------------------------------------
/img/tutorials/1/concept-graph-observablestate-highlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/concept-graph-observablestate-highlight.png
--------------------------------------------------------------------------------
/img/tutorials/1/concept-graph-simaction-highlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/concept-graph-simaction-highlight.png
--------------------------------------------------------------------------------
/img/tutorials/1/moab-frame-of-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/moab-frame-of-reference.png
--------------------------------------------------------------------------------
/img/tutorials/1/moab-photo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/moab-photo.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-assessment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-assessment.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-concept-graph-training-mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-concept-graph-training-mode.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-create-brain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-create-brain.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-inkling-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-inkling-view.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-starting-assessment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-starting-assessment.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-starting-training.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-starting-training.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-training-converged.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-training-converged.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-training-started-perf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-training-started-perf.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-training-started.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-training-started.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-training-stopped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-training-stopped.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-ui-sections.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-ui-sections.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-visualizer-and-sim-chart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-visualizer-and-sim-chart.png
--------------------------------------------------------------------------------
/img/tutorials/1/tutorial1-visualizer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/1/tutorial1-visualizer.png
--------------------------------------------------------------------------------
/img/tutorials/3/assessment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/3/assessment.png
--------------------------------------------------------------------------------
/img/tutorials/3/bonsai-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/3/bonsai-home.png
--------------------------------------------------------------------------------
/img/tutorials/3/converged.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/3/converged.png
--------------------------------------------------------------------------------
/img/tutorials/3/select-simulator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/3/select-simulator.png
--------------------------------------------------------------------------------
/img/tutorials/img01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/img01.png
--------------------------------------------------------------------------------
/img/tutorials/img01.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/img01.tif
--------------------------------------------------------------------------------
/img/tutorials/img02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/img02.png
--------------------------------------------------------------------------------
/img/tutorials/img03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/img03.png
--------------------------------------------------------------------------------
/img/tutorials/img04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/img04.png
--------------------------------------------------------------------------------
/img/tutorials/img05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/img05.png
--------------------------------------------------------------------------------
/img/tutorials/img06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/img06.png
--------------------------------------------------------------------------------
/img/tutorials/img07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/img07.png
--------------------------------------------------------------------------------
/img/tutorials/img08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/img08.png
--------------------------------------------------------------------------------
/img/tutorials/perf-chart-converged.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/perf-chart-converged.png
--------------------------------------------------------------------------------
/img/tutorials/tutorial2-converging-goal-sat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/tutorial2-converging-goal-sat.png
--------------------------------------------------------------------------------
/img/tutorials/tutorial2-select-sim.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/tutorials/tutorial2-select-sim.png
--------------------------------------------------------------------------------
/img/viewer/camera-module.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/viewer/camera-module.jpg
--------------------------------------------------------------------------------
/img/viewer/control-arms.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/viewer/control-arms.jpg
--------------------------------------------------------------------------------
/img/viewer/m2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/viewer/m2.jpg
--------------------------------------------------------------------------------
/img/viewer/power-control-board.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/viewer/power-control-board.jpg
--------------------------------------------------------------------------------
/img/viewer/raspberry-pi-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/viewer/raspberry-pi-4.jpg
--------------------------------------------------------------------------------
/img/viewer/servos.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moab/bc3242bddd985e971cf73eab518c58d79685e353/img/viewer/servos.jpg
--------------------------------------------------------------------------------
/js/app.js:
--------------------------------------------------------------------------------
1 | import '../scss/app.scss';
2 | import Sketchfab from './sketchfab-viewer-1.7.1';
3 | import './jquery-global';
4 | import fancyBox from './../node_modules/@fancyapps/fancybox/dist/jquery.fancybox';
5 |
6 | document.querySelector(".hamburger").addEventListener('click', function () {
7 | document.querySelector("nav > ul").classList.toggle("active");
8 | });
9 |
10 | (function () {
11 | // Sketchfab
12 | var iframe = document.getElementById( 'api-frame' );
13 | if (iframe) {
14 | var uid = 'aa056783e78445f19182dad31d99935f';
15 | var client = new Sketchfab( iframe );
16 | client.init( uid, {
17 | transparent: 1,
18 | ui_controls: 0,
19 | ui_infos: 0,
20 | success: function onSuccess( api ){
21 | api.start(function () {
22 | // Handles the buttons outside of sketchfab
23 | var buttons = document.getElementsByClassName('sketchfab-button');
24 | for (let button of buttons) {
25 | button.addEventListener('click', function (e) {
26 | e.preventDefault();
27 | api.gotoAnnotation(button.getAttribute('annotation'), {});
28 | for(let b of buttons) {
29 | b.classList.remove('active');
30 | }
31 | button.classList.toggle('active');
32 | });
33 | }
34 | });
35 | }
36 | });
37 | }
38 |
39 | //moab viewer
40 | var buttons = document.getElementsByClassName('viewer-button');
41 | var imgs = document.getElementsByClassName('moab-viewer-image');
42 | for (let i = 0; i < buttons.length; i++) {
43 | buttons[i].addEventListener('mouseover', function (e) {
44 | document.querySelector('.viewer-button.active').classList.remove('active');
45 | document.querySelector('.moab-viewer-image.active').classList.remove('active');
46 | e.target.classList.add('active');
47 | imgs[i].classList.add('active');
48 | });
49 | }
50 |
51 | //expand content
52 | var expandButtons = document.querySelectorAll('.expand-button');
53 | for (let button of expandButtons) {
54 | button.addEventListener('click', function (e) {
55 | if (e && e.target) {
56 | var parent = e.target.closest('.section');
57 | var button = e.target;
58 | var right = parent.querySelector('.right');
59 | right.classList.toggle('expand');
60 | button.classList.toggle('expand-button')
61 | button.classList.toggle('close-button')
62 | }
63 | });
64 | }
65 |
66 | //expand content on url pound
67 | var hash = window.location.hash;
68 | if (hash) {
69 | var expand = document.getElementById(window.location.hash.split('#')[1]);
70 | if (expand) {
71 | expand.querySelector('.expand-button').click();
72 | }
73 | }
74 |
75 | })();
76 |
--------------------------------------------------------------------------------
/js/jquery-global.js:
--------------------------------------------------------------------------------
1 | import jquery from 'jquery';
2 | window.jQuery = jquery;
3 | window.$ = jquery;
--------------------------------------------------------------------------------
/js/sketchfab-viewer-1.7.1.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Sketchfab=e():t.Sketchfab=e()}(window,(function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var s=e[n]={i:n,l:!1,exports:{}};return t[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var s in t)i.d(n,s,function(e){return t[e]}.bind(null,s));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="/static/builds/web/dist/",i(i.s=1)}([function(t,e){function i(t){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function n(e){return"function"==typeof Symbol&&"symbol"===i(Symbol.iterator)?t.exports=n=function(t){return i(t)}:t.exports=n=function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":i(t)},n(e)}t.exports=n},function(t,e,i){"use strict";i.r(e);var n=i(0),s=i.n(n),r=function(t,e){t.forEach((function(t){this[t]=function(){var i,n=e._requestIdCounter++,s=Array.prototype.slice.call(arguments);if(s.length>0){var r=s[s.length-1];"function"==typeof r&&(i=s.pop())}i&&(e._pendingRequests[n]=i.bind(this)),e._target.postMessage({type:"api.request",instanceId:e.getIdentifier(),requestId:n,member:t,arguments:s},e.getDomain())}}),this),this.addEventListener=function(t,i,n){"viewerready"===t&&e.isViewerReady&&i(),e._eventListeners[t]||(e._eventListeners[t]=[]),e._eventListeners[t].push(i),n&&this.setListenerOptions&&(n.name=t,this.setListenerOptions(n))},this.removeEventListener=function(t,i){if(e._eventListeners[t]){var n=e._eventListeners[t].indexOf(i);-1!==n&&e._eventListeners[t].splice(n,1)}}},o=function(t,e,i){this._target=t,this._requestIdCounter=0,this._pendingRequests={},this._eventListeners={},this._ready=!1,this._domain=i,this._instanceId=e,this.listenServer()};o.prototype={getIdentifier:function(){return this._instanceId},getDomain:function(){return this._domain},setIdentifier:function(t){this._instanceId=t},use:function(t,e){this._version=t,this._ready=!0;var i=this._requestIdCounter++;this._pendingRequests[i]=function(t,i,n){t?e.call(this,t):e.call(this,null,new r(n,this))}.bind(this),this._target.postMessage({type:"api.initialize",requestId:i,name:t,instanceId:this._instanceId},this._domain)},listenServer:function(){var t=["api.initialize.result","api.request.result","api.event"];window.addEventListener("message",function(e){if(e.origin===this._domain&&e.data&&e.data.type&&e.data.instanceId&&e.data.instanceId===this.getIdentifier()){var i=e.data.type;if(-1!==t.indexOf(i))if("api.event"===i){var n=e.data.results,s=n[0];if(this._eventListeners["*"]||this._eventListeners.all)return void["*","all"].forEach((function(t){var e=this._eventListeners[t];e&&e.forEach((function(t){t.apply(t,n)}))}),this);var r=n.slice(1),o=this._eventListeners[s];o?o.forEach((function(t){t.apply(t,r)})):"viewerready"===s&&(this.isViewerReady=!0)}else{var a=e.data.requestId,u=this._pendingRequests[a];if(!u)return;u.apply(null,e.data.results),this._pendingRequests[a]=void 0}}}.bind(this))}};var a=o,u=/[&|;]+/g;function d(t){var e={};return Object.keys(t).forEach((function(i){e[i]=Array.isArray(t[i])?t[i]:[t[i]]})),e}function c(t){return"object"===s()(t)?d(t):("?"===t[0]&&(t=t.substr(1)),t.split(u).reduce((function(t,e){if(0===e.length)return t;var i=e.indexOf("=");-1===i&&(i=e.length);var n=decodeURIComponent(e.substr(0,i).replace(/\+/g,"%20")),s=decodeURIComponent(e.substr(i+1).replace(/\+/g,"%20"));return void 0===t[n]&&(t[n]=[]),t[n].push(s),t}),{}))}window.SketchfabAPIClient=a;var h=function(t,e){var i=t,n=e;"object"===s()(t)&&(n=t,i=null),this._version=i,this._target=n,window.sketchfabAPIinstances||(window.sketchfabAPIinstances=[]),window.sketchfabAPIinstances.push(this),this._apiId=window.sketchfabAPIinstances.length.toString(),this._target.id&&(this._apiId+="_"+this._target.id),this._target.allow||(this._target.allow="vr; autoplay; fullscreen"),this._client=void 0,this._options=void 0,this._domain="sketchfab.com",this._domain="same-as-current"===this._domain?window.location.hostname:this._domain,this._urlTemplate="https://YYYY/models/XXXX/embed",this._url=this._urlTemplate.replace("YYYY",this._domain),this._transmitOptions={},this._getURLOptions()};h.prototype={_urlOptionsDict:{skfb_api_version:{default:"1.7.1",type:"string"}},_optionsLoaded:function(t){this._urlOptions=t,this._version=this._getURLOption("skfb_api_version",this._version)},_getURLOption:function(t,e){var i=this._urlOptionsDict[t];if(!i)return e;null==e&&(e=i.default);var n=this._urlOptions[t];return n&&n.length?n[0]:e},_getURLOptions:function(){if(!window||!window.location.search)return this._optionsLoaded({});var t=c(window.location.search);for(var e in t)e.startsWith("skfb_")&&(this._transmitOptions[e.substr(5)]=t[e]);return this._optionsLoaded(t)},getEmbedURL:function(t,e){var i=this._url+"?api_version="+this._version+"&api_id="+this._apiId;e&&Object.keys(e).forEach((function(t){null!=e[t]&&"function"!=typeof e[t]&&(i+="&"+t.toString()+"="+e[t].toString())}));var n=this._transmitOptions;return Object.keys(this._transmitOptions).forEach((function(t){i+="&"+t.toString()+"="+n[t].toString()})),i.replace("XXXX",t)},init:function(t,e){this._options=e,this._uid=t,this._realInit()},reload:function(t){var e=document.createElement("script");e.setAttribute("src","https://static."+t+"/api/sketchfab-viewer-"+this._version+".js"),e.addEventListener("load",function(){this._url=this._urlTemplate.replace("YYYY",t),-1!==this._domain.indexOf("sketchfab.com")&&(this._transmitOptions.hook_prod=1,this._transmitOptions.model=this._uid),this._realInit()}.bind(this)),document.body.appendChild(e)},_initializeAPIEmbed:function(t){if(t.data&&t.data.instanceId&&this._apiId===t.data.instanceId&&"api.ready"===t.data.type&&this._target.src){var e=t.data.options;if(e&&e.domain)this.reload(e.domain);else{if(void 0!==t.data.error)return this.error(t.data.error),void window.removeEventListener("message",this._initializeAPIEmbedBinded);var i=this._target.src.split("/");i="https://"+i[2],this._client=new window.SketchfabAPIClient(this._target.contentWindow,this._apiId,i),this._client.use(this._version,function(t,e){if(t)throw t;this.success.call(this,e)}.bind(this)),window.removeEventListener("message",this._initializeAPIEmbedBinded)}}},_realInit:function(){this._initializeAPIEmbedBinded=this._initializeAPIEmbed.bind(this),window.addEventListener("message",this._initializeAPIEmbedBinded),this._target.src=this.getEmbedURL(this._uid,this._options)},success:function(t){this._options.success&&"function"==typeof this._options.success&&this._options.success(t)},error:function(t){this._options.error&&"function"==typeof this._options.error&&this._options.error(t)},show:function(){var t=this._target.style.top;this._target.style.top="-1000vh",Promise.resolve().then(function(){this._target.style.top=t}.bind(this))}};e.default=h}]).default}));
2 | //# sourceMappingURL=sketchfab-viewer-1.7.1.js.map
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "project-moab",
3 | "version": "1.1.0",
4 | "description": "Project Moab",
5 | "main": "index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/scotstan/moab"
9 | },
10 | "scripts": {
11 | "dev": "ELEVENTY_ENV=development npm-run-all --parallel dev:*",
12 | "prod": "ELEVENTY_ENV=production npm-run-all prod:encore prod:eleventy",
13 | "deploy": "npm-run-all prod gh-pages",
14 | "clean": "rm -rf {build,dist,node_modules}",
15 | "dev:eleventy": "eleventy --config=11ty.js --serve --quiet",
16 | "dev:encore": "encore dev --watch",
17 | "prod:eleventy": "eleventy --config=11ty.js",
18 | "prod:encore": "encore production",
19 | "gh-pages": "gh-pages -d dist"
20 | },
21 | "author": "Scott Stanfield ",
22 | "license": "MIT",
23 | "devDependencies": {
24 | "@11ty/eleventy": ">0.10",
25 | "@11ty/eleventy-navigation": "^0.1.5",
26 | "http-server": "^0.12.3",
27 | "sass-loader": "^10.0.0"
28 | },
29 | "dependencies": {
30 | "@11ty/eleventy-plugin-syntaxhighlight": "^2.0.3",
31 | "@fancyapps/fancybox": "^3.5.7",
32 | "@symfony/webpack-encore": "^0.33.0",
33 | "all-contributors-cli": "^6.14.0",
34 | "gh-pages": "^2.2.0",
35 | "jquery": "^3.5.1",
36 | "npm-run-all": "^4.1.5",
37 | "prism-themes": "^1.3.0",
38 | "prod": "^1.0.1",
39 | "sass": "^1.30.0",
40 | "share-api-polyfill": "^1.0.11"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/scss/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 0;
3 | margin: 0;
4 | font-family: "Roboto Mono", monospace;
5 | }
6 | .splash {
7 | background-color: #fff;
8 | }
9 | .splash .bg {
10 | height: 100vh;
11 | opacity: 0.2;
12 | background: no-repeat center url("../img/background-dark.svg");
13 | background-size: 3500px;
14 | }
15 | .splash .headline-container {
16 | display: flex;
17 | flex-direction: column;
18 | justify-content: center;
19 | align-items: center;
20 | height: 100vh;
21 | width: 100%;
22 | position: absolute;
23 | top: 0;
24 | left: 0;
25 | }
26 | .splash .headline-container .headline {
27 | margin-top: -10px;
28 | }
29 | .splash .headline-container .headline h1 {
30 | font-weight: bold;
31 | font-size: 40px;
32 | margin: 0;
33 | color: #3b3b3b;
34 | }
35 | .splash .headline-container .headline .typewriter {
36 | margin-top: 10px;
37 | color: #ee7100;
38 | letter-spacing: 16px;
39 | text-transform: uppercase;
40 | overflow: hidden;
41 | white-space: nowrap;
42 | border-right: 0.45em solid #ee7100;
43 | animation: typing 3s steps(45, end), blink-caret 0.8s step-end infinite;
44 | }
45 | @keyframes typing {
46 | from {
47 | width: 0;
48 | }
49 | to {
50 | width: 100%;
51 | }
52 | }
53 | @keyframes blink-caret {
54 | from,
55 | to {
56 | border-color: transparent;
57 | }
58 | 50% {
59 | border-color: #ee7100;
60 | }
61 | }
62 | @media (prefers-color-scheme: dark) {
63 | .splash {
64 | background-color: #3b3b3b;
65 | }
66 | .splash .bg {
67 | background: no-repeat center url("../img/background-light.svg");
68 | background-size: 3500px;
69 | }
70 | .splash .headline-container .headline h1 {
71 | color: #fff;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/scss/app.scss:
--------------------------------------------------------------------------------
1 |
2 | $dark: #3B3B3B;
3 | $light: #fff;
4 | $orange: #EE7100;
5 | $grey: #C4C4C4;
6 | $light-grey: #F4F4F4;
7 |
8 | @import url("https://use.typekit.net/zfi0znh.css");
9 | @import url("../node_modules/@fancyapps/fancybox/dist/jquery.fancybox.min.css");
10 | @import "./buttons.scss";
11 |
12 | /* common styles */
13 |
14 | body {
15 | font-family: 'Segoe UI', sans-serif;
16 | font-size: 16px;
17 | color: $dark;
18 | margin: 0;
19 | }
20 |
21 | img {
22 | max-width: 100%;
23 | }
24 |
25 | .page-wrap {
26 | max-width: 1440px;
27 | margin: 0 auto;
28 | }
29 |
30 | footer {
31 | background-color: $dark;
32 | height: 300px;
33 | margin-top: 200px;
34 | padding-top: 30px;
35 | color: $light;
36 | }
37 |
38 | hr {
39 | border: 0;
40 | border-bottom: 1px solid $grey;
41 | margin-top: 280px;
42 | margin-bottom: 280px;
43 | }
44 |
45 | a {
46 | text-decoration: none;
47 | color: $dark;
48 | white-space: nowrap;
49 | }
50 |
51 | .lnk {
52 | background: none;
53 | border: none;
54 | padding: 0;
55 | cursor: pointer;
56 | outline: none;
57 | }
58 |
59 | .mt-160 {
60 | margin-top: 160px;
61 | }
62 |
63 | .section, .subsection {
64 | margin-left: 120px;
65 | margin-right: 120px;
66 | }
67 |
68 | .subsection {
69 | margin-top: 150px;
70 | margin-bottom: 0;
71 | padding-bottom: 50px;
72 |
73 | &:first-of-type {
74 | margin-top: 100px;
75 | }
76 | }
77 |
78 | h1{
79 | font-family: 'din-2014', 'Segoe UI', sans-serif;
80 | text-transform: uppercase;
81 | font-size: 64px;
82 | margin-bottom: 0;
83 | }
84 |
85 | h2 {
86 | font-size: 40px;
87 | }
88 |
89 | h3 {
90 | font-size: 40px;
91 | font-weight: normal;
92 | margin-top: 105px;
93 | margin-bottom: 0;
94 | border-bottom: 1px solid $grey;
95 | padding-bottom: 54px;
96 | }
97 |
98 | .subheading {
99 | font-size: 24px;
100 | font-weight: bold;
101 | }
102 |
103 | .subheading2 {
104 | font-size: 24px;
105 | margin-top: 15px;
106 | margin-bottom: 60px;
107 | }
108 |
109 | .subheading3 {
110 | font-size: 16px;
111 | font-weight: bold;
112 | }
113 |
114 |
115 | td, th {
116 | padding-right: 30px;
117 | text-align: left;
118 | }
119 |
120 |
121 | /* top nav */
122 | nav {
123 | font-family: 'din-2014', 'Roboto Mono', monospace;
124 | padding: 0 120px;
125 | font-style: normal;
126 | font-weight: 600;
127 |
128 | ul {
129 | width: 100%;
130 | margin-top: 70px;
131 | padding-inline-start: 0;
132 | display: flex;
133 | list-style-type: none;
134 | flex-direction: row;
135 | height: 30px;
136 |
137 | li {
138 | margin-right: 63px;
139 | font-size: 16px;
140 | text-transform: uppercase;
141 |
142 | a {
143 | padding-bottom: 9px;
144 | }
145 |
146 | &.active {
147 | a {
148 | display: inline-block;
149 | border-bottom: 2px solid $orange;
150 | padding-bottom: 9px;
151 | }
152 | }
153 |
154 | &:hover {
155 | a {
156 | display: inline-block;
157 | border-bottom: 2px solid $orange;
158 | padding-bottom: 9px;
159 | }
160 | }
161 |
162 | &:last-child {
163 | flex: 2;
164 | text-align: end;
165 | margin: -10px 0 0 0;
166 | a {
167 | font-weight: bold;
168 | color: $orange;
169 | border-bottom: none;
170 | }
171 | }
172 | }
173 | }
174 | }
175 |
176 |
177 | /* front page section */
178 | .hero1, .tech-spec, .teach, .get-started {
179 | position: relative;
180 | .subheading2 {
181 | max-width: 600px;
182 | }
183 | h2 {
184 | margin-bottom: 24px;
185 | }
186 | }
187 |
188 | .hero2 {
189 | text-align: center;
190 | margin-top: 160px;
191 |
192 | .machine-header {
193 | font-family: 'din-2014', 'Segoe UI', sans-serif;
194 | text-transform: uppercase;
195 | font-size: 55px;
196 | font-weight: bold;
197 | }
198 |
199 | .subheading2 {
200 | margin-bottom: 50px;
201 | }
202 |
203 | img {
204 | width: 100%;
205 | }
206 | }
207 |
208 | .hero1 {
209 | background: url('../img/Hero\ 2_04-29-20.png') no-repeat;
210 | background-position: top;
211 | height: 890px;
212 | width: 100vw;
213 | position: relative;
214 | left: calc(-50vw + 50%);
215 |
216 | .section {
217 | max-width: 1440px;
218 | margin-left: auto;
219 | margin-right: auto;
220 | }
221 | h2, .subheading2, .content {
222 | border: 0;
223 | margin-left: 120px;
224 | margin-right: 120px;
225 | max-width: 600px;
226 | }
227 | }
228 |
229 | .background-video {
230 | margin-top: 200px;
231 | margin-bottom: 200px;
232 | width: 100vw;
233 | position: relative;
234 | left: calc(-50vw + 50%);
235 |
236 | .background-text-wrapper {
237 | margin-left: auto;
238 | margin-right: auto;
239 | width: 1440px;
240 | }
241 |
242 | .section {
243 | display: flex;
244 | align-items: center;
245 | width: 100%;
246 | height: 100%;
247 | margin-left: auto;
248 | margin-right: auto;
249 | position: absolute;
250 | color: white;
251 | z-index: 1;
252 |
253 | h2, .subheading2, .content {
254 | border: 0;
255 | margin-left: 120px;
256 | margin-right: 120px;
257 | max-width: 600px;
258 | }
259 | }
260 | .video-wrapper {
261 | background-color: black;
262 | video {
263 | width: 100%;
264 | opacity: 0.3;
265 | }
266 | }
267 | }
268 |
269 | .get-started {
270 | h2 {
271 | text-align: center;
272 | }
273 | .subheading2 {
274 | max-width: 725px;
275 | margin-left: auto;
276 | margin-right: auto;
277 | text-align: center;
278 | }
279 | .tiles {
280 | justify-content: space-around;
281 | }
282 | }
283 |
284 | .teach {
285 | img {
286 | margin-top: 125px;
287 | margin-left: -30px;
288 | width: 120%;
289 | }
290 | }
291 |
292 | .content {
293 | &.moab-viewer {
294 | display: flex;
295 |
296 | .left {
297 | min-width: 300px;
298 | display: flex;
299 | flex-direction: column;
300 |
301 | .moab-viewer-links {
302 | font-family: 'din-2014', 'Roboto Mono', monospace;
303 | margin: 120px 0 0 70px;
304 |
305 | div {
306 | margin-top: 38px;
307 | }
308 |
309 | span {
310 | cursor:pointer;
311 | font-size: 16px;
312 | text-transform: uppercase;
313 | display: inline-block;
314 | padding-bottom: 10px;
315 |
316 | &.active {
317 | border-bottom: 1px solid $orange;
318 | }
319 | }
320 | }
321 | }
322 |
323 | .right {
324 | width: 52vw;
325 | height: 52vw;
326 |
327 | img {
328 | position: absolute;
329 | width: 52vw;
330 | height: 52vw;
331 | object-fit: contain;
332 | opacity: 0;
333 | transition: opacity 1.0s ease-in-out;
334 |
335 | &.active {
336 | opacity: 1;
337 | }
338 | }
339 | }
340 | }
341 | }
342 |
343 | /* tiles (download page and index page) */
344 | .tiles {
345 | display: flex;
346 | flex-wrap: wrap;
347 |
348 | a {
349 | margin-bottom: 16px;
350 | margin-top: 16px;
351 | }
352 | .tile {
353 | display: flex;
354 | position: relative;
355 | flex-direction: column;
356 | align-items: center;
357 | box-shadow: 0px 2px 15px rgba(59, 59, 59, 0.1);
358 | width: 300px;
359 | height: 300px;
360 | margin-right: 35px;
361 | margin-left: 35px;
362 | border: 1px solid $grey;
363 | transition: all 0.2s ease-in-out;
364 | font-weight: bold;
365 |
366 | .tile-top {
367 | display: flex;
368 | width: 100%;
369 | height: 200px;
370 | background-color: $light-grey;
371 | justify-items: center;
372 | align-items: center;
373 |
374 | img {
375 | margin-left: auto;
376 | margin-right: auto;
377 | }
378 |
379 | span {
380 | width: 300px;
381 | height: 200px;
382 | position: absolute;
383 | display: block;
384 | top: 0;
385 | left: 0;
386 | background: url('../img/icons/play.svg') center center no-repeat rgba(0, 0, 0, 0.3);
387 |
388 | &.no-image {
389 | background: url('../img/icons/play.svg') center center no-repeat rgba(0, 0, 0, 0.0);
390 | }
391 | }
392 | }
393 |
394 | .tile-bottom {
395 | display: flex;
396 | height: 100px;
397 | align-items: center;
398 | }
399 |
400 | &:hover {
401 | transition: all 0.2s ease-in-out;
402 | transform: translateY(-2px);
403 | box-shadow: 0px 2px 15px rgba(59, 59, 59, 0.4);
404 | }
405 | }
406 | }
407 |
408 | /* expanding / link block sections */
409 | .tutorial-item {
410 | display: flex;
411 | border-bottom: 1px solid $grey;
412 | padding: 65px 0 65px 0;
413 |
414 | .right {
415 | font-size: 22px;
416 | margin-left: 10px;
417 |
418 | a {
419 | display: inline-block;
420 | padding-bottom: 2px;
421 | font-weight: 500;
422 | color: $orange
423 | }
424 |
425 | .summary {
426 | margin-top: 5px;
427 | max-width: 75%;
428 | }
429 |
430 | .subheading {
431 | transition: color 1s ease;
432 | }
433 |
434 | .details {
435 | transition: margin 1s, max-height 1s, opacity 1s;
436 | opacity: 0;
437 | max-height: 0;
438 | overflow: hidden;
439 | }
440 |
441 | &.expand {
442 | .subheading {
443 | transition: color 1s ease;
444 | color: $orange;
445 | }
446 | .details {
447 | height: auto;
448 | max-height: 600px;
449 | margin-top: 40px;
450 | opacity: 1;
451 | transition: margin 1s , max-height 1s, opacity 1s;
452 | }
453 | }
454 | }
455 | }
456 |
457 | .download {
458 | display: flex;
459 | max-width: 600px;
460 | height: 100px;
461 | border: 1px solid $grey;
462 | box-shadow: 0px 2px 15px rgba(59, 59, 59, 0.1);
463 | align-items: center;
464 | margin-top: 25px;
465 | transition: all 0.2s ease-in-out;
466 |
467 | .content {
468 | margin-left: 20px;
469 | }
470 |
471 | &:hover {
472 | transition: all 0.2s ease-in-out;
473 | transform: translateY(-2px);
474 | box-shadow: 0px 2px 15px rgba(59, 59, 59, 0.4);
475 | }
476 | }
477 |
478 | h3 + .download {
479 | margin-top: 55px;
480 | }
481 |
482 | // assets page
483 | .gallery {
484 | margin-top: 50px;
485 | display: grid;
486 | grid-template-columns: repeat(4, 1fr);
487 | grid-gap: 15px;
488 |
489 | img {
490 | width: 100%;
491 | height: 100%;
492 | object-fit: cover;
493 | }
494 | }
495 |
496 | .sketchfab {
497 | display: flex;
498 |
499 | .left {
500 | min-width: 300px;
501 | display: flex;
502 | flex-direction: column;
503 | div {
504 | margin: 22px 0;
505 | a {
506 | font-size: 16px;
507 | text-transform: uppercase;
508 | padding: 0;
509 |
510 | &.active {
511 | border-bottom: 1px solid $orange;
512 | }
513 | }
514 | }
515 | }
516 |
517 | .right {
518 | iframe {
519 | width: 60vw;
520 | height: 40vw;
521 | }
522 | }
523 | }
524 |
525 | /* tutorial specific markdown */
526 |
527 | .md {
528 |
529 | margin-left: auto;
530 | margin-right: auto;
531 | max-width: 800px;
532 |
533 | h1, h2, h3 {
534 | margin-top: 20px;
535 | margin-bottom: 0px;
536 | border: 0;
537 | padding-bottom: 10px;
538 | }
539 |
540 | h3 {
541 | margin-top:20px;
542 | font-size: 32px;
543 | }
544 |
545 | img {
546 | max-width: 800px;
547 | margin-left: auto;
548 | margin-right: auto;
549 | display: block;
550 | }
551 |
552 | a {
553 | display: inline-block;
554 | padding-bottom: 2px;
555 | color: $orange;
556 | }
557 | }
558 |
559 | @media only screen and (max-width: 870px) {
560 | nav {
561 | padding: 30px 30px 0 0;
562 | text-align: right;
563 |
564 | ul {
565 | text-align: right;
566 | display: none;
567 | margin-top: 0;
568 |
569 | &.active {
570 | display: block;
571 | }
572 |
573 | li {
574 | margin: 0;
575 |
576 | &:last-child {
577 | margin: 0;
578 | }
579 | }
580 | }
581 |
582 | .hamburger {
583 | display: inline-block;
584 | }
585 | }
586 |
587 | .hero1 {
588 | .section {
589 | margin: 0;
590 | .subheading2, h2, .content {
591 | margin-left: 10px;
592 | margin-right: 10px;
593 | }
594 | }
595 | }
596 |
597 | .background-video {
598 | width: 220vw;
599 | .background-text-wrapper {
600 | max-width: 100vw;
601 | margin: 0 10px;
602 | .subheading2, h2, .content {
603 | margin-left: 10px;
604 | margin-right: 10px;
605 | }
606 | }
607 | }
608 |
609 | .teach {
610 | img {
611 | margin: 100px 10px;
612 | width: 100%;
613 | }
614 | }
615 | .content {
616 | &.sketchfab, &.moab-viewer {
617 | display: flex;
618 | flex-direction: column;
619 | }
620 |
621 | &.tile {
622 | display: flex;
623 | flex-wrap: wrap;
624 | }
625 | }
626 |
627 | .section, .subsection, .md {
628 | margin-left: 10px;
629 | margin-right: 10px;
630 | }
631 | }
632 |
--------------------------------------------------------------------------------
/scss/buttons.scss:
--------------------------------------------------------------------------------
1 | /* buttons */
2 |
3 | @mixin animated-button($url) {
4 | font-family: 'Roboto Mono', monospace;
5 | font-weight: bold;
6 | display: inline-block;
7 | align-items: center;
8 | transition: color 0.75s ease;
9 | background: none;
10 | color: $orange;
11 | position: relative;
12 | text-transform: uppercase;
13 | padding-right: 25px;
14 | z-index: 1;
15 |
16 | &::before {
17 | content:"";
18 | background: url($url) no-repeat;
19 | display: inline-block;
20 | height: 50px;
21 | width: 50px;
22 | margin-right: 13px;
23 | vertical-align: middle;
24 | }
25 |
26 | &:hover {
27 | color: #fff;
28 | }
29 |
30 | &::after {
31 | position: absolute;
32 | content: '';
33 | top:0;
34 | left: 0;
35 | width: 0;
36 | height: 100%;
37 | background-color: $orange;
38 | transform-origin:right;
39 | transition:width 0.75s ease;
40 | z-index:-1;
41 | }
42 |
43 | &:hover::after {
44 | width: 100%;
45 | }
46 | }
47 |
48 | @mixin animated-button-right($url) {
49 | font-family: 'Roboto Mono', monospace;
50 | font-weight: bold;
51 | display: inline-block;
52 | align-items: center;
53 | transition: color 0.75s ease;
54 | background: none;
55 | color: $orange;
56 | position: relative;
57 | text-transform: uppercase;
58 | padding-left: 25px;
59 | z-index: 1;
60 |
61 | &::after {
62 | content:"";
63 | background: url($url) no-repeat;
64 | display: inline-block;
65 | height: 50px;
66 | width: 50px;
67 | margin-left: 13px;
68 | vertical-align: middle;
69 | }
70 |
71 | &:hover {
72 | color: #fff;
73 | }
74 |
75 | &::before {
76 | position: absolute;
77 | content: '';
78 | top:0;
79 | right: 0;
80 | width: 0;
81 | height: 100%;
82 | background-color: $orange;
83 | transform-origin:right;
84 | transition:width 0.75s ease;
85 | z-index:-1;
86 | }
87 |
88 | &:hover::before {
89 | width: 100%;
90 | }
91 | }
92 |
93 | @mixin simple-button($url) {
94 | cursor:pointer;
95 | display: inline-block;
96 | color: $orange;
97 | position: relative;
98 | z-index: 1;
99 |
100 | &::before {
101 | content:"";
102 | background: url($url) no-repeat;
103 | transition: background-image 0.5s ease-in-out;
104 | display: inline-block;
105 | height: 50px;
106 | width: 50px;
107 | margin-right: 13px;
108 | vertical-align: middle;
109 | }
110 | }
111 |
112 | .internal-button-animate {
113 | @include animated-button('../img/icons/internal.svg');
114 | }
115 |
116 | .external-button-animate {
117 | @include animated-button('../img/icons/external.svg');
118 | }
119 |
120 | .play-button-animate {
121 | @include animated-button('../img/icons/video.svg');
122 | }
123 |
124 | .internal-button-right-animate {
125 | @include animated-button-right('../img/icons/internal.svg');
126 | }
127 |
128 | .external-button-right-animate {
129 | @include animated-button-right('../img/icons/external.svg');
130 | }
131 |
132 | .play-button-right-animate {
133 | @include animated-button-right('../img/icons/video.svg');
134 | }
135 |
136 |
137 | /* simple buttons */
138 | .expand-button {
139 | @include simple-button('../img/icons/expand.svg');
140 | }
141 |
142 | .close-button {
143 | @include simple-button('../img/icons/close.svg');
144 | }
145 |
146 | .external-button {
147 | @include simple-button('../img/icons/external.svg');
148 | }
149 |
150 |
151 | .download-button {
152 | cursor:pointer;
153 | display: inline-block;
154 | color: $orange;
155 | position: relative;
156 | z-index: 1;
157 |
158 | &::before {
159 | content:"";
160 | background: url('../img/icons/download.svg') no-repeat;
161 | display: inline-block;
162 | height: 100px;
163 | width: 50px;
164 | vertical-align: middle;
165 | }
166 | }
167 |
168 | /* hamburger */
169 | .hamburger {
170 | position: relative;
171 | display: none;
172 | width: 1.25em;
173 | height: 0.8em;
174 | margin-right: 0.3em;
175 | border-top: 0.2em solid $grey;
176 | border-bottom: 0.2em solid $grey;
177 | font-size: 20px;
178 | }
179 |
180 | .hamburger:before {
181 | content: "";
182 | position: absolute;
183 | top: 0.3em;
184 | left: 0px;
185 | width: 100%;
186 | border-top: 0.2em solid $grey;
187 | }
188 |
189 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const Encore = require('@symfony/webpack-encore');
2 |
3 | Encore
4 | .setOutputPath('build')
5 | //.setPublicPath('/fresh-moab-sandbox/build') //for fresh site directory
6 | .setPublicPath('/build')
7 | .setManifestKeyPrefix('build')
8 | .addEntry('app', './js/app.js')
9 | .enableSingleRuntimeChunk()
10 | .enableSourceMaps(!Encore.isProduction())
11 | .enableSassLoader()
12 | ;
13 |
14 | if (Encore.isProduction()) {
15 | Encore
16 | .setPublicPath('/moab/build')
17 | .cleanupOutputBeforeBuild()
18 | .enableVersioning()
19 | ;
20 | }
21 |
22 | module.exports = Encore.getWebpackConfig();
23 |
--------------------------------------------------------------------------------